From 7a358806f3947c1284ff6cbd196a6b0ee51c1d83 Mon Sep 17 00:00:00 2001 From: Pilar Date: Mon, 21 Nov 2022 11:03:28 -0500 Subject: [PATCH 1/8] starting with the nrcan_usage_parameters class. Not working! --- .../data_models/usages/internal_gain.py | 1 + catalog_factories/usage/comnet_catalog.py | 4 +- .../building_demand/internal_zone.py | 4 +- .../building_demand/thermal_zone.py | 4 +- .../{usage_zone.py => usage.py} | 18 ++++----- exports/formats/energy_ade.py | 2 +- exports/formats/idf.py | 28 +++++++------- imports/geometry/helpers/geometry_helper.py | 4 ++ .../schedules/comnet_schedules_parameters.py | 2 +- imports/schedules/doe_idf.py | 2 +- imports/usage/comnet_usage_parameters.py | 8 ++-- imports/usage/hft_usage_interface.py | 14 +++---- imports/usage/nrcan_usage_parameters.py | 38 +++++++++++++++++++ unittests/test_construction_factory.py | 2 +- unittests/test_enrichement.py | 2 +- unittests/test_usage_factory.py | 2 +- 16 files changed, 89 insertions(+), 46 deletions(-) rename city_model_structure/building_demand/{usage_zone.py => usage.py} (97%) create mode 100644 imports/usage/nrcan_usage_parameters.py diff --git a/catalog_factories/data_models/usages/internal_gain.py b/catalog_factories/data_models/usages/internal_gain.py index ee7a0ec8..f1d8ad7f 100644 --- a/catalog_factories/data_models/usages/internal_gain.py +++ b/catalog_factories/data_models/usages/internal_gain.py @@ -5,6 +5,7 @@ Copyright © 2022 Concordia CERC group Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca """ + class InternalGain: """ InternalGain class diff --git a/catalog_factories/usage/comnet_catalog.py b/catalog_factories/usage/comnet_catalog.py index e2fb294d..0667d94d 100644 --- a/catalog_factories/usage/comnet_catalog.py +++ b/catalog_factories/usage/comnet_catalog.py @@ -220,7 +220,7 @@ class ComnetCatalog(Catalog): """ _names = {'usages': []} for usage in self._content.usages: - _names['usages'].append(usage.usage) + _names['usages'].append(usage.name) return _names def entries(self, category=None): @@ -236,6 +236,6 @@ class ComnetCatalog(Catalog): :parm: entry name """ for usage in self._content.usages: - if usage.usage.lower() == name.lower(): + if usage.name.lower() == name.lower(): return usage raise IndexError(f"{name} doesn't exists in the catalog") diff --git a/city_model_structure/building_demand/internal_zone.py b/city_model_structure/building_demand/internal_zone.py index 8c1d3376..6c1a536e 100644 --- a/city_model_structure/building_demand/internal_zone.py +++ b/city_model_structure/building_demand/internal_zone.py @@ -7,7 +7,7 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca import uuid from typing import Union, List -from city_model_structure.building_demand.usage_zone import UsageZone +from city_model_structure.building_demand.usage import Usage from city_model_structure.building_demand.thermal_zone import ThermalZone from city_model_structure.attributes.polyhedron import Polyhedron from city_model_structure.energy_systems.hvac_system import HvacSystem @@ -75,7 +75,7 @@ class InternalZone: return self._area @property - def usage_zones(self) -> [UsageZone]: + def usage_zones(self) -> [Usage]: """ Get internal zone usage zones :return: [UsageZone] diff --git a/city_model_structure/building_demand/thermal_zone.py b/city_model_structure/building_demand/thermal_zone.py index 417a6b39..f3b09d1f 100644 --- a/city_model_structure/building_demand/thermal_zone.py +++ b/city_model_structure/building_demand/thermal_zone.py @@ -67,7 +67,7 @@ class ThermalZone: self._usage_zones = [] for parent_usage_zone in self._parent_internal_zone.usage_zones: for value in usages: - if parent_usage_zone.usage == value[1]: + if parent_usage_zone.name == value[1]: new_usage_zone = copy.deepcopy(parent_usage_zone) new_usage_zone.percentage = float(value[0])/100 self._usage_zones.append(new_usage_zone) @@ -234,7 +234,7 @@ class ThermalZone: return None self._usage = '' for usage_zone in self._parent_internal_zone.usage_zones: - self._usage += str(round(usage_zone.percentage * 100)) + '-' + usage_zone.usage + '_' + self._usage += str(round(usage_zone.percentage * 100)) + '-' + usage_zone.name + '_' self._usage = self._usage[:-1] return self._usage diff --git a/city_model_structure/building_demand/usage_zone.py b/city_model_structure/building_demand/usage.py similarity index 97% rename from city_model_structure/building_demand/usage_zone.py rename to city_model_structure/building_demand/usage.py index 225f9cb2..0a86b625 100644 --- a/city_model_structure/building_demand/usage_zone.py +++ b/city_model_structure/building_demand/usage.py @@ -1,5 +1,5 @@ """ -UsageZone module +Usage module SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2022 Concordia CERC group Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca @@ -15,13 +15,13 @@ from city_model_structure.building_demand.thermal_control import ThermalControl from city_model_structure.building_demand.internal_gain import InternalGain -class UsageZone: +class Usage: """ - UsageZone class + Usage class """ def __init__(self): self._id = None - self._usage = None + self._name = None self._percentage = None self._internal_gains = None self._hours_day = None @@ -44,21 +44,21 @@ class UsageZone: return self._id @property - def usage(self) -> Union[None, str]: + def name(self) -> Union[None, str]: """ Get usage zone usage :return: None or str """ - return self._usage + return self._name - @usage.setter - def usage(self, value): + @name.setter + def name(self, value): """ Set usage zone usage :param value: str """ if value is not None: - self._usage = str(value) + self._name = str(value) @property def percentage(self): diff --git a/exports/formats/energy_ade.py b/exports/formats/energy_ade.py index 8e618f4f..9b9d1e6e 100644 --- a/exports/formats/energy_ade.py +++ b/exports/formats/energy_ade.py @@ -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.usage for u in building.usage_zones]) + building_dic['bldg:Building']['bldg:usage'] = ', '.join([u.name for u in building.usage_zones]) 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'] = { diff --git a/exports/formats/idf.py b/exports/formats/idf.py index 5972a991..f5487b78 100644 --- a/exports/formats/idf.py +++ b/exports/formats/idf.py @@ -226,9 +226,9 @@ class Idf: _schedule.values = _infiltration_values _infiltration_schedules.append(_schedule) for schedule in self._idf.idfobjects[self._HOURLY_SCHEDULE]: - if schedule.Name == f'Infiltration schedules {thermal_zone.usage}': + if schedule.Name == f'Infiltration schedules {thermal_zone.name}': return - return self._add_standard_compact_hourly_schedule(thermal_zone.usage, 'Infiltration', _infiltration_schedules) + return self._add_standard_compact_hourly_schedule(thermal_zone.name, 'Infiltration', _infiltration_schedules) def _add_people_activity_level_schedules(self, thermal_zone): _occ = thermal_zone.occupancy @@ -238,9 +238,9 @@ class Idf: _total_heat = (_occ.sensible_convective_internal_gain + _occ.sensible_radiative_internal_gain + _occ.latent_internal_gain) / _occ.occupancy_density for schedule in self._idf.idfobjects[self._COMPACT_SCHEDULE]: - if schedule.Name == f'Activity Level schedules {thermal_zone.usage}': + if schedule.Name == f'Activity Level schedules {thermal_zone.name}': return - _kwargs = {'Name': f'Activity Level schedules {thermal_zone.usage}', + _kwargs = {'Name': f'Activity Level schedules {thermal_zone.name}', 'Schedule_Type_Limits_Name': self.idf_type_limits[cte.ANY_NUMBER], 'Field_1': 'Through: 12/31', 'Field_2': 'For AllDays', @@ -319,15 +319,15 @@ class Idf: self._add_heating_system(thermal_zone, name) def _add_thermostat(self, thermal_zone): - thermostat_name = f'Thermostat {thermal_zone.usage}' + thermostat_name = f'Thermostat {thermal_zone.name}' for thermostat in self._idf.idfobjects[self._THERMOSTAT]: if thermostat.Name == thermostat_name: return thermostat # todo: change schedules to schedule name and create schedules using the add_schedule function return self._idf.newidfobject(self._THERMOSTAT, Name=thermostat_name, - Heating_Setpoint_Schedule_Name=f'Heating thermostat schedules {thermal_zone.usage}', - Cooling_Setpoint_Schedule_Name=f'Cooling thermostat schedules {thermal_zone.usage}') + Heating_Setpoint_Schedule_Name=f'Heating thermostat schedules {thermal_zone.name}', + Cooling_Setpoint_Schedule_Name=f'Cooling thermostat schedules {thermal_zone.name}') def _add_heating_system(self, thermal_zone, zone_name): for air_system in self._idf.idfobjects[self._IDEAL_LOAD_AIR_SYSTEM]: @@ -336,9 +336,9 @@ class Idf: thermostat = self._add_thermostat(thermal_zone) self._idf.newidfobject(self._IDEAL_LOAD_AIR_SYSTEM, Zone_Name=zone_name, - System_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage}', - Heating_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage}', - Cooling_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage}', + System_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.name}', + Heating_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.name}', + Cooling_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.name}', Template_Thermostat_Name=thermostat.Name) def _add_occupancy(self, thermal_zone, zone_name): @@ -349,11 +349,11 @@ class Idf: self._idf.newidfobject(self._PEOPLE, Name=f'{zone_name}_occupancy', Zone_or_ZoneList_Name=zone_name, - Number_of_People_Schedule_Name=f'Occupancy schedules {thermal_zone.usage}', + Number_of_People_Schedule_Name=f'Occupancy schedules {thermal_zone.name}', Number_of_People_Calculation_Method="People", Number_of_People=number_of_people, Fraction_Radiant=fraction_radiant, - Activity_Level_Schedule_Name=f'Activity Level schedules {thermal_zone.usage}' + Activity_Level_Schedule_Name=f'Activity Level schedules {thermal_zone.name}' ) def _add_infiltration(self, thermal_zone, zone_name): @@ -363,7 +363,7 @@ class Idf: self._idf.newidfobject(self._INFILTRATION, Name=f'{zone_name}_infiltration', Zone_or_ZoneList_Name=zone_name, - Schedule_Name=f'Infiltration schedules {thermal_zone.usage}', + Schedule_Name=f'Infiltration schedules {thermal_zone.name}', Design_Flow_Rate_Calculation_Method='AirChanges/Hour', Air_Changes_per_Hour=thermal_zone.mechanical_air_change ) @@ -405,7 +405,7 @@ class Idf: self._add_vegetation_material(thermal_boundary.parent_surface.vegetation) for thermal_opening in thermal_boundary.thermal_openings: self._add_window_construction_and_material(thermal_opening) - usage = thermal_zone.usage + usage = thermal_zone.name if building.name in self._target_buildings or building.name in self._adjacent_buildings: self._add_infiltration_schedules(thermal_zone) self._add_schedules(usage, 'Occupancy', thermal_zone.occupancy.occupancy_schedules) diff --git a/imports/geometry/helpers/geometry_helper.py b/imports/geometry/helpers/geometry_helper.py index 8a9f5951..b43487d4 100644 --- a/imports/geometry/helpers/geometry_helper.py +++ b/imports/geometry/helpers/geometry_helper.py @@ -228,6 +228,10 @@ class GeometryHelper: 'office': cte.MEDIUM_OFFICE, 'large office': cte.LARGE_OFFICE } + # function + _alkis_to_function = { + + } # usage _function_to_usage = { diff --git a/imports/schedules/comnet_schedules_parameters.py b/imports/schedules/comnet_schedules_parameters.py index deaca3b0..0f957306 100644 --- a/imports/schedules/comnet_schedules_parameters.py +++ b/imports/schedules/comnet_schedules_parameters.py @@ -23,7 +23,7 @@ class ComnetSchedules: for usage_zone in building.usage_zones: schedules = [] usage_schedules = pd.read_excel(xls, - sheet_name=SchedulesHelper.comnet_from_usage(usage_zone.usage), + sheet_name=SchedulesHelper.comnet_from_usage(usage_zone.name), skiprows=[0, 1, 2, 3], nrows=39, usecols="A:AA") number_of_schedule_types = 13 schedules_per_schedule_type = 3 diff --git a/imports/schedules/doe_idf.py b/imports/schedules/doe_idf.py index eeb72168..18048efc 100644 --- a/imports/schedules/doe_idf.py +++ b/imports/schedules/doe_idf.py @@ -59,7 +59,7 @@ class DoeIdf: for usage_zone in internal_zone.usage_zones: for schedule_archetype in self._schedule_library['archetypes']['archetypes']: function = schedule_archetype['@building_type'] - if SchedulesHelper.usage_from_function(function) == usage_zone.usage: + if SchedulesHelper.usage_from_function(function) == usage_zone.name: self._idf_schedules_path = (base_path / schedule_archetype['idf']['path']).resolve() with open(self._idf_schedules_path, 'r') as file: idf = parseidf.parse(file.read()) diff --git a/imports/usage/comnet_usage_parameters.py b/imports/usage/comnet_usage_parameters.py index 8ad563f9..a9505f83 100644 --- a/imports/usage/comnet_usage_parameters.py +++ b/imports/usage/comnet_usage_parameters.py @@ -15,7 +15,7 @@ from helpers.configuration_helper import ConfigurationHelper as ch from imports.geometry.helpers.geometry_helper import GeometryHelper from imports.usage.helpers.usage_helper import UsageHelper from imports.schedules.helpers.schedules_helper import SchedulesHelper -from city_model_structure.building_demand.usage_zone import UsageZone +from city_model_structure.building_demand.usage import Usage from city_model_structure.building_demand.lighting import Lighting from city_model_structure.building_demand.occupancy import Occupancy from city_model_structure.building_demand.appliances import Appliances @@ -74,7 +74,7 @@ class ComnetUsageParameters: @staticmethod def _parse_usage_type(comnet_usage, data, schedules_data): - _usage_zone = UsageZone() + _usage_zone = Usage() # lighting _lighting = Lighting() @@ -213,8 +213,8 @@ class ComnetUsageParameters: if internal_zone.volume <= 0: raise Exception('Internal zone volume is zero, ACH cannot be calculated') volume_per_area = internal_zone.volume / internal_zone.area - usage_zone = UsageZone() - usage_zone.usage = usage + usage_zone = Usage() + usage_zone.name = usage self._assign_values_usage_zone(usage_zone, archetype_usage, volume_per_area) usage_zone.percentage = 1 self._calculate_reduced_values_from_extended_library(usage_zone, archetype_usage) diff --git a/imports/usage/hft_usage_interface.py b/imports/usage/hft_usage_interface.py index 0eeea969..e44832d4 100644 --- a/imports/usage/hft_usage_interface.py +++ b/imports/usage/hft_usage_interface.py @@ -7,7 +7,7 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca """ import xmltodict import copy -from city_model_structure.building_demand.usage_zone import UsageZone +from city_model_structure.building_demand.usage import Usage from city_model_structure.building_demand.internal_gain import InternalGain from city_model_structure.building_demand.occupancy import Occupancy from city_model_structure.building_demand.appliances import Appliances @@ -39,8 +39,8 @@ class HftUsageInterface: @staticmethod def _parse_zone_usage_type(usage, zone_usage_type): - usage_zone_archetype = UsageZone() - usage_zone_archetype.usage = usage + usage_zone_archetype = Usage() + usage_zone_archetype.name = usage if 'occupancy' in zone_usage_type: _occupancy = Occupancy() @@ -153,7 +153,7 @@ class HftUsageInterface: def _parse_zone_usage_variant(usage, usage_zone, usage_zone_variant): # the variants mimic the inheritance concept from OOP usage_zone_archetype = copy.deepcopy(usage_zone) - usage_zone_archetype.usage = usage + usage_zone_archetype.name = usage if 'occupancy' in usage_zone_variant: _occupancy = Occupancy() @@ -262,14 +262,14 @@ class HftUsageInterface: def _search_archetype(self, libs_usage): building_usage = UsageHelper().hft_from_libs_usage(libs_usage) for building_archetype in self._usage_archetypes: - if building_archetype.usage == building_usage: + if building_archetype.name == building_usage: return building_archetype return None @staticmethod def _assign_values(usage, archetype): - usage_zone = UsageZone() - usage_zone.usage = usage + usage_zone = Usage() + usage_zone.name = usage usage_zone.internal_gains = copy.deepcopy(archetype.internal_gains) usage_zone.mechanical_air_change = archetype.mechanical_air_change usage_zone.occupancy = copy.deepcopy(archetype.occupancy) diff --git a/imports/usage/nrcan_usage_parameters.py b/imports/usage/nrcan_usage_parameters.py new file mode 100644 index 00000000..19034827 --- /dev/null +++ b/imports/usage/nrcan_usage_parameters.py @@ -0,0 +1,38 @@ +""" +NrcanUsageParameters imports the usage information for Canada and feeds the central data model classes with it +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca +""" + +from catalog_factories.usage_catalog_factory import UsageCatalogFactory + +class NrcanUsageParameters: + """ + NrcanUsageParameters class + """ + @staticmethod + def _search_archetype(usage_name, year_of_construction, climate_zone): + nrcan_catalog = UsageCatalogFactory('nrcan').catalog + nrcan_archetypes = nrcan_catalog.entries('archetypes') + for building_archetype in nrcan_archetypes: + + return None + + @staticmethod + def _search_usage_in_archetype(archetype, usage_name): + usage_archetypes = archetype. + for usage_archetype in archetypes_archetypes: + if str(usage_name) == str(usage_archetype.type): + return usage_archetype + return None + + def _assign_values(self, usage, archetype): + for thermal_zone in thermal_zones: + thermal_zone.additional_thermal_bridge_u_value = archetype.extra_loses_due_to_thermal_bridges + + def enrich_buildings(self): + """ + Raise not implemented error + """ + raise NotImplementedError diff --git a/unittests/test_construction_factory.py b/unittests/test_construction_factory.py index 6ca15a2c..a3f43e38 100644 --- a/unittests/test_construction_factory.py +++ b/unittests/test_construction_factory.py @@ -122,7 +122,7 @@ class TestConstructionFactory(TestCase): self.assertIsNone(thermal_zone.ordinate_number, 'thermal_zone ordinate number is not none') self.assertIsNotNone(thermal_zone.view_factors_matrix, 'thermal_zone view factors matrix is none') self.assertIsNotNone(thermal_zone.total_floor_area, 'thermal zone total_floor_area is none') - self.assertIsNone(thermal_zone.usage, 'thermal_zone usage is not none') + self.assertIsNone(thermal_zone.name, 'thermal_zone usage is not none') self.assertIsNone(thermal_zone.hours_day, 'thermal_zone hours a day is not none') self.assertIsNone(thermal_zone.days_year, 'thermal_zone days a year is not none') self.assertIsNone(thermal_zone.mechanical_air_change, 'thermal_zone mechanical air change is not none') diff --git a/unittests/test_enrichement.py b/unittests/test_enrichement.py index 16831dea..f8cc2011 100644 --- a/unittests/test_enrichement.py +++ b/unittests/test_enrichement.py @@ -55,7 +55,7 @@ class TestGeometryFactory(TestCase): def _check_thermal_zone(self, thermal_zone): self.assertIsNotNone(thermal_zone.id, 'thermal_zone id is none') - self.assertIsNotNone(thermal_zone.usage, 'thermal_zone usage is not none') + self.assertIsNotNone(thermal_zone.name, 'thermal_zone usage is not none') self.assertIsNotNone(thermal_zone.hours_day, 'thermal_zone hours a day is none') self.assertIsNotNone(thermal_zone.days_year, 'thermal_zone days a year is none') self.assertIsNotNone(thermal_zone.occupancy, 'thermal_zone occupancy is none') diff --git a/unittests/test_usage_factory.py b/unittests/test_usage_factory.py index 15138579..0267f703 100644 --- a/unittests/test_usage_factory.py +++ b/unittests/test_usage_factory.py @@ -70,7 +70,7 @@ class TestUsageFactory(TestCase): self.assertTrue(building.is_conditioned, 'building is not conditioned') def _check_usage_zone(self, usage_zone): - self.assertIsNotNone(usage_zone.usage, 'usage is none') + self.assertIsNotNone(usage_zone.name, 'usage is none') self.assertIsNotNone(usage_zone.percentage, 'usage percentage is none') self.assertIsNotNone(usage_zone.hours_day, 'hours per day is none') self.assertIsNotNone(usage_zone.days_year, 'days per year is none') From 1f3320c02a4e366a9f23d5b9638d459409031fb3 Mon Sep 17 00:00:00 2001 From: Pilar Date: Tue, 6 Dec 2022 15:28:59 -0500 Subject: [PATCH 2/8] cleaning not used classes --- city_model_structure/building.py | 4 +- .../building_demand/internal_zone.py | 12 +- .../building_demand/thermal_zone.py | 10 +- exports/building_energy/energy_ade.py | 4 +- exports/building_energy/idf.py | 30 ++-- .../insel/insel_monthly_energy_balance.py | 4 +- helpers/monthly_to_hourly_demand.py | 4 +- .../data_classes/building_achetype.py | 98 ------------- .../data_classes/layer_archetype.py | 104 ------------- .../thermal_boundary_archetype.py | 137 ------------------ .../data_classes/thermal_opening_archetype.py | 131 ----------------- .../helpers/storeys_generation.py | 4 +- .../construction/nrel_physics_interface.py | 71 --------- ...rameters.py => nrel_physics_parameters.py} | 59 +++++++- imports/construction_factory.py | 6 +- imports/usage/ca_usage_parameters.py | 41 ------ imports/usage/comnet_usage_parameters.py | 22 +-- imports/usage/hft_usage_parameters.py | 2 +- imports/usage/nrcan_usage_parameters.py | 38 ----- imports/usage_factory.py | 4 +- unittests/test_construction_factory.py | 2 +- unittests/test_enrichement.py | 8 +- unittests/test_geometry_factory.py | 2 +- unittests/test_insel_exports.py | 14 +- unittests/test_usage_factory.py | 10 +- 25 files changed, 125 insertions(+), 696 deletions(-) delete mode 100644 imports/construction/data_classes/building_achetype.py delete mode 100644 imports/construction/data_classes/layer_archetype.py delete mode 100644 imports/construction/data_classes/thermal_boundary_archetype.py delete mode 100644 imports/construction/data_classes/thermal_opening_archetype.py delete mode 100644 imports/construction/nrel_physics_interface.py rename imports/construction/{us_physics_parameters.py => nrel_physics_parameters.py} (74%) delete mode 100644 imports/usage/ca_usage_parameters.py delete mode 100644 imports/usage/nrcan_usage_parameters.py diff --git a/city_model_structure/building.py b/city_model_structure/building.py index 97f643d1..43090b1d 100644 --- a/city_model_structure/building.py +++ b/city_model_structure/building.py @@ -397,8 +397,8 @@ class Building(CityObject): if self.internal_zones is None: return False for internal_zone in self.internal_zones: - if internal_zone.usage_zones is not None: - for usage_zone in internal_zone.usage_zones: + if internal_zone.usages is not None: + for usage_zone in internal_zone.usages: if usage_zone.thermal_control is not None: return True return False diff --git a/city_model_structure/building_demand/internal_zone.py b/city_model_structure/building_demand/internal_zone.py index 6c1a536e..ddbb3b8c 100644 --- a/city_model_structure/building_demand/internal_zone.py +++ b/city_model_structure/building_demand/internal_zone.py @@ -24,7 +24,7 @@ class InternalZone: self._volume = None self._area = area self._thermal_zones = None - self._usage_zones = None + self._usages = None self._hvac_system = None @property @@ -75,20 +75,20 @@ class InternalZone: return self._area @property - def usage_zones(self) -> [Usage]: + def usages(self) -> [Usage]: """ Get internal zone usage zones :return: [UsageZone] """ - return self._usage_zones + return self._usages - @usage_zones.setter - def usage_zones(self, value): + @usages.setter + def usages(self, value): """ Set internal zone usage zones :param value: [UsageZone] """ - self._usage_zones = value + self._usages = value @property def hvac_system(self) -> Union[None, HvacSystem]: diff --git a/city_model_structure/building_demand/thermal_zone.py b/city_model_structure/building_demand/thermal_zone.py index 1e66402e..c09b8acf 100644 --- a/city_model_structure/building_demand/thermal_zone.py +++ b/city_model_structure/building_demand/thermal_zone.py @@ -58,14 +58,14 @@ class ThermalZone: def usage_zones(self): # example 70-office_30-residential if self._usage_from_parent: - self._usages = copy.deepcopy(self._parent_internal_zone.usage_zones) + self._usages = copy.deepcopy(self._parent_internal_zone.usages) else: values = self._usage.split('_') usages = [] for value in values: usages.append(value.split('-')) self._usages = [] - for parent_usage in self._parent_internal_zone.usage_zones: + for parent_usage in self._parent_internal_zone.usages: for value in usages: if parent_usage.usage == value[1]: new_usage = copy.deepcopy(parent_usage) @@ -230,11 +230,11 @@ class ThermalZone: :return: None or str """ if self._usage_from_parent: - if self._parent_internal_zone.usage_zones is None: + if self._parent_internal_zone.usages is None: return None self._usage = '' - for usage_zone in self._parent_internal_zone.usage_zones: - self._usage += str(round(usage_zone.percentage * 100)) + '-' + usage_zone.usage + '_' + for usage_zone in self._parent_internal_zone.usages: + self._usage += str(round(usage_zone.percentage * 100)) + '-' + usage_zone.name + '_' self._usage = self._usage[:-1] return self._usage diff --git a/exports/building_energy/energy_ade.py b/exports/building_energy/energy_ade.py index 9b9d1e6e..1ccd8d2a 100644 --- a/exports/building_energy/energy_ade.py +++ b/exports/building_energy/energy_ade.py @@ -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.usage_zones]) + building_dic['bldg:Building']['bldg:usage'] = ', '.join([u.name for u in building.usages]) 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'] = { @@ -266,7 +266,7 @@ class EnergyAde: thermal_zones = [] for index, thermal_zone in enumerate(building.thermal_zones): usage_zones = [] - for usage_zone in thermal_zone.usage_zones: + for usage_zone in thermal_zone.usages: usage_zones.append({'@xlink:href': f'#GML_{usage_zone.id}'}) thermal_zone_dic = { 'energy:ThermalZone': { diff --git a/exports/building_energy/idf.py b/exports/building_energy/idf.py index 57cad3c1..43fa23d0 100644 --- a/exports/building_energy/idf.py +++ b/exports/building_energy/idf.py @@ -207,9 +207,9 @@ class Idf: _schedule.values = _infiltration_values _infiltration_schedules.append(_schedule) for schedule in self._idf.idfobjects[self._HOURLY_SCHEDULE]: - if schedule.Name == f'Infiltration schedules {thermal_zone.name}': + if schedule.Name == f'Infiltration schedules {thermal_zone.usage}': return - return self._add_standard_compact_hourly_schedule(thermal_zone.name, 'Infiltration', _infiltration_schedules) + return self._add_standard_compact_hourly_schedule(thermal_zone.usage, 'Infiltration', _infiltration_schedules) def _add_people_activity_level_schedules(self, thermal_zone): _occ = thermal_zone.occupancy @@ -219,9 +219,9 @@ class Idf: _total_heat = (_occ.sensible_convective_internal_gain + _occ.sensible_radiative_internal_gain + _occ.latent_internal_gain) / _occ.occupancy_density for schedule in self._idf.idfobjects[self._COMPACT_SCHEDULE]: - if schedule.Name == f'Activity Level schedules {thermal_zone.name}': + if schedule.Name == f'Activity Level schedules {thermal_zone.usage}': return - _kwargs = {'Name': f'Activity Level schedules {thermal_zone.name}', + _kwargs = {'Name': f'Activity Level schedules {thermal_zone.usage}', 'Schedule_Type_Limits_Name': self.idf_type_limits[cte.ANY_NUMBER], 'Field_1': 'Through: 12/31', 'Field_2': 'For AllDays', @@ -300,15 +300,15 @@ class Idf: self._add_heating_system(thermal_zone, name) def _add_thermostat(self, thermal_zone): - thermostat_name = f'Thermostat {thermal_zone.name}' + thermostat_name = f'Thermostat {thermal_zone.usage}' for thermostat in self._idf.idfobjects[self._THERMOSTAT]: if thermostat.Name == thermostat_name: return thermostat # todo: change schedules to schedule name and create schedules using the add_schedule function return self._idf.newidfobject(self._THERMOSTAT, Name=thermostat_name, - Heating_Setpoint_Schedule_Name=f'Heating thermostat schedules {thermal_zone.name}', - Cooling_Setpoint_Schedule_Name=f'Cooling thermostat schedules {thermal_zone.name}') + Heating_Setpoint_Schedule_Name=f'Heating thermostat schedules {thermal_zone.usage}', + Cooling_Setpoint_Schedule_Name=f'Cooling thermostat schedules {thermal_zone.usage}') def _add_heating_system(self, thermal_zone, zone_name): for air_system in self._idf.idfobjects[self._IDEAL_LOAD_AIR_SYSTEM]: @@ -317,9 +317,9 @@ class Idf: thermostat = self._add_thermostat(thermal_zone) self._idf.newidfobject(self._IDEAL_LOAD_AIR_SYSTEM, Zone_Name=zone_name, - System_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.name}', - Heating_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.name}', - Cooling_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.name}', + System_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage}', + Heating_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage}', + Cooling_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage}', Template_Thermostat_Name=thermostat.Name) def _add_occupancy(self, thermal_zone, zone_name): @@ -330,11 +330,11 @@ class Idf: self._idf.newidfobject(self._PEOPLE, Name=f'{zone_name}_occupancy', Zone_or_ZoneList_Name=zone_name, - Number_of_People_Schedule_Name=f'Occupancy schedules {thermal_zone.name}', + Number_of_People_Schedule_Name=f'Occupancy schedules {thermal_zone.usage}', Number_of_People_Calculation_Method="People", Number_of_People=number_of_people, Fraction_Radiant=fraction_radiant, - Activity_Level_Schedule_Name=f'Activity Level schedules {thermal_zone.name}' + Activity_Level_Schedule_Name=f'Activity Level schedules {thermal_zone.usage}' ) def _add_infiltration(self, thermal_zone, zone_name): @@ -344,7 +344,7 @@ class Idf: self._idf.newidfobject(self._INFILTRATION, Name=f'{zone_name}_infiltration', Zone_or_ZoneList_Name=zone_name, - Schedule_Name=f'Infiltration schedules {thermal_zone.name}', + Schedule_Name=f'Infiltration schedules {thermal_zone.usage}', Design_Flow_Rate_Calculation_Method='AirChanges/Hour', Air_Changes_per_Hour=thermal_zone.mechanical_air_change ) @@ -387,7 +387,7 @@ class Idf: self._add_vegetation_material(thermal_boundary.parent_surface.vegetation) for thermal_opening in thermal_boundary.thermal_openings: self._add_window_construction_and_material(thermal_opening) - usage = thermal_zone.name + usage = thermal_zone.usage if building.name in self._target_buildings or building.name in self._adjacent_buildings: self._add_infiltration_schedules(thermal_zone) self._add_schedules(usage, 'Occupancy', thermal_zone.occupancy.occupancy_schedules) @@ -449,7 +449,7 @@ class Idf: if surface.Type == self.idf_surfaces[boundary.surface.type]: surface.Construction_Name = boundary.construction_name break - for usage_zone in thermal_zone.usage_zones: + for usage_zone in thermal_zone.usages: surface.Zone_Name = usage_zone.id break break diff --git a/exports/building_energy/insel/insel_monthly_energy_balance.py b/exports/building_energy/insel/insel_monthly_energy_balance.py index 55f08443..262c2b4d 100644 --- a/exports/building_energy/insel/insel_monthly_energy_balance.py +++ b/exports/building_energy/insel/insel_monthly_energy_balance.py @@ -77,9 +77,9 @@ class InselMonthlyEnergyBalance(Insel): parameters.append('1 % BP(9) Usage type (0=standard, 1=IWU)') # ZONES AND SURFACES - parameters.append(f'{len(internal_zone.usage_zones)} % BP(10) Number of zones') + parameters.append(f'{len(internal_zone.usages)} % BP(10) Number of zones') - for i, usage_zone in enumerate(internal_zone.usage_zones): + for i, usage_zone in enumerate(internal_zone.usages): percentage_usage = usage_zone.percentage parameters.append(f'{float(internal_zone.area) * percentage_usage} % BP(11) #1 Area of zone {i + 1} (m2)') total_internal_gain = 0 diff --git a/helpers/monthly_to_hourly_demand.py b/helpers/monthly_to_hourly_demand.py index bc7d11d4..1dfeb5ad 100644 --- a/helpers/monthly_to_hourly_demand.py +++ b/helpers/monthly_to_hourly_demand.py @@ -29,7 +29,7 @@ class MonthlyToHourlyDemand: # todo: this method and the insel model have to be reviewed for more than one thermal zone external_temp = self._building.external_temperature[cte.HOUR] # todo: review index depending on how the schedules are defined, either 8760 or 24 hours - for usage_zone in self._building.usage_zones: + for usage_zone in self._building.usages: temp_set = float(usage_zone.heating_setpoint)-3 temp_back = float(usage_zone.heating_setback)-3 # todo: if these are data frames, then they should be called as (Occupancy should be in low case): @@ -90,7 +90,7 @@ class MonthlyToHourlyDemand: # todo: this method and the insel model have to be reviewed for more than one thermal zone external_temp = self._building.external_temperature[cte.HOUR] # todo: review index depending on how the schedules are defined, either 8760 or 24 hours - for usage_zone in self._building.usage_zones: + for usage_zone in self._building.usages: temp_set = float(usage_zone.cooling_setpoint) temp_back = 100 occupancy = Occupant().get_complete_year_schedule(usage_zone.schedules['Occupancy']) diff --git a/imports/construction/data_classes/building_achetype.py b/imports/construction/data_classes/building_achetype.py deleted file mode 100644 index 708549b5..00000000 --- a/imports/construction/data_classes/building_achetype.py +++ /dev/null @@ -1,98 +0,0 @@ -""" -BuildingArchetype stores construction information by building archetypes -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Concordia CERC group -Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca -""" -from typing import List -from imports.construction.data_classes.thermal_boundary_archetype import ThermalBoundaryArchetype - - -class BuildingArchetype: - """ - BuildingArchetype class - """ - def __init__(self, archetype_keys, average_storey_height, storeys_above_ground, effective_thermal_capacity, - additional_thermal_bridge_u_value, indirectly_heated_area_ratio, infiltration_rate_system_off, - infiltration_rate_system_on, thermal_boundary_archetypes): - self._archetype_keys = archetype_keys - self._average_storey_height = average_storey_height - self._storeys_above_ground = storeys_above_ground - self._effective_thermal_capacity = effective_thermal_capacity - self._additional_thermal_bridge_u_value = additional_thermal_bridge_u_value - self._indirectly_heated_area_ratio = indirectly_heated_area_ratio - self._infiltration_rate_system_off = infiltration_rate_system_off - self._infiltration_rate_system_on = infiltration_rate_system_on - self._thermal_boundary_archetypes = thermal_boundary_archetypes - - @property - def archetype_keys(self) -> {}: - """ - Get keys that define the archetype - :return: dictionary - """ - return self._archetype_keys - - @property - def average_storey_height(self): - """ - Get archetype's building storey height in meters - :return: float - """ - return self._average_storey_height - - @property - def storeys_above_ground(self): - """ - Get archetype's building storey height in meters - :return: float - """ - return self._storeys_above_ground - - @property - def effective_thermal_capacity(self): - """ - Get archetype's effective thermal capacity in J/m2K - :return: float - """ - return self._effective_thermal_capacity - - @property - def additional_thermal_bridge_u_value(self): - """ - Get archetype's additional U value due to thermal bridges per area of shell in W/m2K - :return: float - """ - return self._additional_thermal_bridge_u_value - - @property - def indirectly_heated_area_ratio(self): - """ - Get archetype's indirectly heated area ratio - :return: float - """ - return self._indirectly_heated_area_ratio - - @property - def infiltration_rate_system_off(self): - """ - Get archetype's infiltration rate when conditioning systems OFF in air changes per hour (ACH) - :return: float - """ - return self._infiltration_rate_system_off - - @property - def infiltration_rate_system_on(self): - """ - Get archetype's infiltration rate when conditioning systems ON in air changes per hour (ACH) - :return: float - """ - return self._infiltration_rate_system_on - - @property - def thermal_boundary_archetypes(self) -> List[ThermalBoundaryArchetype]: - """ - Get thermal boundary archetypes associated to the building archetype - :return: list of boundary archetypes - """ - return self._thermal_boundary_archetypes diff --git a/imports/construction/data_classes/layer_archetype.py b/imports/construction/data_classes/layer_archetype.py deleted file mode 100644 index ece0efc5..00000000 --- a/imports/construction/data_classes/layer_archetype.py +++ /dev/null @@ -1,104 +0,0 @@ -""" -LayerArchetype stores layer and materials information, complementing the BuildingArchetype class -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Concordia CERC group -Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca -""" - - -class LayerArchetype: - """ - LayerArchetype class - """ - def __init__(self, name, solar_absorptance, thermal_absorptance, visible_absorptance, thickness=None, - conductivity=None, specific_heat=None, density=None, no_mass=False, thermal_resistance=None): - self._thickness = thickness - self._conductivity = conductivity - self._specific_heat = specific_heat - self._density = density - self._solar_absorptance = solar_absorptance - self._thermal_absorptance = thermal_absorptance - self._visible_absorptance = visible_absorptance - self._no_mass = no_mass - self._name = name - self._thermal_resistance = thermal_resistance - - @property - def thickness(self): - """ - Get thickness in meters - :return: float - """ - return self._thickness - - @property - def conductivity(self): - """ - Get conductivity in W/mK - :return: float - """ - return self._conductivity - - @property - def specific_heat(self): - """ - Get specific heat in J/kgK - :return: float - """ - return self._specific_heat - - @property - def density(self): - """ - Get density in kg/m3 - :return: float - """ - return self._density - - @property - def solar_absorptance(self): - """ - Get solar absorptance - :return: float - """ - return self._solar_absorptance - - @property - def thermal_absorptance(self): - """ - Get thermal absorptance - :return: float - """ - return self._thermal_absorptance - - @property - def visible_absorptance(self): - """ - Get visible absorptance - :return: float - """ - return self._visible_absorptance - - @property - def no_mass(self) -> bool: - """ - Get no mass flag - :return: Boolean - """ - return self._no_mass - - @property - def name(self): - """ - Get name - :return: str - """ - return self._name - - @property - def thermal_resistance(self): - """ - Get thermal resistance in m2K/W - :return: float - """ - return self._thermal_resistance diff --git a/imports/construction/data_classes/thermal_boundary_archetype.py b/imports/construction/data_classes/thermal_boundary_archetype.py deleted file mode 100644 index 36ed66bd..00000000 --- a/imports/construction/data_classes/thermal_boundary_archetype.py +++ /dev/null @@ -1,137 +0,0 @@ -""" -ThermalBoundaryArchetype stores thermal boundaries information, complementing the BuildingArchetype class -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Concordia CERC group -Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca -""" -from typing import List - -from imports.construction.data_classes.layer_archetype import LayerArchetype -from imports.construction.data_classes.thermal_opening_archetype import ThermalOpeningArchetype - - -class ThermalBoundaryArchetype: - """ - ThermalBoundaryArchetype class - """ - def __init__(self, boundary_type, window_ratio, construction_name, layers, thermal_opening, - outside_solar_absorptance=None, outside_thermal_absorptance=None, outside_visible_absorptance=None, - overall_u_value=None, shortwave_reflectance=None, inside_emissivity=None, alpha_coefficient=None, - radiative_coefficient=None): - self._boundary_type = boundary_type - self._outside_solar_absorptance = outside_solar_absorptance - self._outside_thermal_absorptance = outside_thermal_absorptance - self._outside_visible_absorptance = outside_visible_absorptance - self._window_ratio = window_ratio - self._construction_name = construction_name - self._overall_u_value = overall_u_value - self._layers = layers - self._thermal_opening_archetype = thermal_opening - self._shortwave_reflectance = shortwave_reflectance - self._inside_emissivity = inside_emissivity - self._alpha_coefficient = alpha_coefficient - self._radiative_coefficient = radiative_coefficient - - @property - def boundary_type(self): - """ - Get type - :return: str - """ - return self._boundary_type - - @property - def outside_solar_absorptance(self): - """ - Get outside solar absorptance - :return: float - """ - return self._outside_solar_absorptance - - @property - def outside_thermal_absorptance(self): - """ - Get outside thermal absorptance - :return: float - """ - return self._outside_thermal_absorptance - - @property - def outside_visible_absorptance(self): - """ - Get outside visible absorptance - :return: float - """ - return self._outside_visible_absorptance - - @property - def window_ratio(self): - """ - Get window ratio - :return: float - """ - return self._window_ratio - - @property - def construction_name(self): - """ - Get construction name - :return: str - """ - return self._construction_name - - @property - def layers(self) -> List[LayerArchetype]: - """ - Get layers - :return: [NrelLayerArchetype] - """ - return self._layers - - @property - def thermal_opening_archetype(self) -> ThermalOpeningArchetype: - """ - Get thermal opening archetype - :return: ThermalOpeningArchetype - """ - return self._thermal_opening_archetype - - @property - def overall_u_value(self): - """ - Get overall U-value in W/m2K - :return: float - """ - return self._overall_u_value - - @property - def shortwave_reflectance(self): - """ - Get shortwave reflectance - :return: float - """ - return self._shortwave_reflectance - - @property - def inside_emissivity(self): - """ - Get emissivity inside - :return: float - """ - return self._inside_emissivity - - @property - def alpha_coefficient(self): - """ - Get alpha coefficient - :return: float - """ - return self._alpha_coefficient - - @property - def radiative_coefficient(self): - """ - Get radiative coefficient - :return: float - """ - return self._radiative_coefficient diff --git a/imports/construction/data_classes/thermal_opening_archetype.py b/imports/construction/data_classes/thermal_opening_archetype.py deleted file mode 100644 index bfa7a026..00000000 --- a/imports/construction/data_classes/thermal_opening_archetype.py +++ /dev/null @@ -1,131 +0,0 @@ -""" -ThermalOpeningArchetype stores thermal openings information, complementing the BuildingArchetype class -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Concordia CERC group -Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca -""" - - -class ThermalOpeningArchetype: - """ - ThermalOpeningArchetype class - """ - def __init__(self, conductivity=None, frame_ratio=None, g_value=None, thickness=None, - back_side_solar_transmittance_at_normal_incidence=None, - front_side_solar_transmittance_at_normal_incidence=None, overall_u_value=None, - openable_ratio=None, inside_emissivity=None, alpha_coefficient=None, radiative_coefficient=None, - construction_name=None): - self._conductivity = conductivity - self._frame_ratio = frame_ratio - self._g_value = g_value - self._thickness = thickness - self._back_side_solar_transmittance_at_normal_incidence = back_side_solar_transmittance_at_normal_incidence - self._front_side_solar_transmittance_at_normal_incidence = front_side_solar_transmittance_at_normal_incidence - self._overall_u_value = overall_u_value - self._openable_ratio = openable_ratio - self._inside_emissivity = inside_emissivity - self._alpha_coefficient = alpha_coefficient - self._radiative_coefficient = radiative_coefficient - self._construction_name = construction_name - - @property - def conductivity(self): - """ - Get conductivity in W/mK - :return: float - """ - return self._conductivity - - @property - def frame_ratio(self): - """ - Get frame ratio - :return: float - """ - return self._frame_ratio - - @property - def g_value(self): - """ - Get g-value, also called shgc - :return: float - """ - return self._g_value - - @property - def thickness(self): - """ - Get thickness in meters - :return: float - """ - return self._thickness - - @property - def back_side_solar_transmittance_at_normal_incidence(self): - """ - Get back side solar transmittance at normal incidence - :return: float - """ - return self._back_side_solar_transmittance_at_normal_incidence - - @property - def front_side_solar_transmittance_at_normal_incidence(self): - """ - Get front side solar transmittance at normal incidence - :return: float - """ - return self._front_side_solar_transmittance_at_normal_incidence - - @property - def overall_u_value(self): - """ - Get overall U-value in W/m2K - :return: float - """ - return self._overall_u_value - - @property - def openable_ratio(self): - """ - Get openable ratio - :return: float - """ - return self._openable_ratio - - @property - def inside_emissivity(self): - """ - Get emissivity inside - :return: float - """ - return self._inside_emissivity - - @property - def alpha_coefficient(self): - """ - Get alpha coefficient - :return: float - """ - return self._alpha_coefficient - - @property - def radiative_coefficient(self): - """ - Get radiative coefficient - :return: float - """ - return self._radiative_coefficient - - @property - def construction_name(self): - """ - Get thermal opening construction name - """ - return self._construction_name - - @construction_name.setter - def construction_name(self, value): - """ - Set thermal opening construction name - """ - self._construction_name = value diff --git a/imports/construction/helpers/storeys_generation.py b/imports/construction/helpers/storeys_generation.py index 19bad00e..4dbe7ab6 100644 --- a/imports/construction/helpers/storeys_generation.py +++ b/imports/construction/helpers/storeys_generation.py @@ -49,7 +49,7 @@ class StoreysGeneration: thermal_zones = [storey.thermal_zone] else: # internal thermal boundary -> two thermal zones - grad = np.rad2deg(thermal_boundary.inclination) + grad = np.rad2deg(thermal_boundary.parent_surface.inclination) if grad >= 170: thermal_zones = [storey.thermal_zone, storey.neighbours[0]] else: @@ -116,7 +116,7 @@ class StoreysGeneration: thermal_zones = [storey.thermal_zone] else: # internal thermal boundary -> two thermal zones - grad = np.rad2deg(thermal_boundary.inclination) + grad = np.rad2deg(thermal_boundary.parent_surface.inclination) if grad >= 170: thermal_zones = [storey.thermal_zone, storey.neighbours[0]] else: diff --git a/imports/construction/nrel_physics_interface.py b/imports/construction/nrel_physics_interface.py deleted file mode 100644 index 354b3176..00000000 --- a/imports/construction/nrel_physics_interface.py +++ /dev/null @@ -1,71 +0,0 @@ -""" -Nrel-based interface, it reads format defined within the CERC team based on NREL structure -and enriches the city with archetypes and materials -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Concordia CERC group -Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca -""" - -from imports.construction.helpers.storeys_generation import StoreysGeneration - - -class NrelPhysicsInterface: - """ - NrelPhysicsInterface abstract class - """ - - # todo: verify windows - @staticmethod - def _calculate_view_factors(thermal_zone): - """ - Get thermal zone view factors matrix - :return: [[float]] - """ - total_area = 0 - for thermal_boundary in thermal_zone.thermal_boundaries: - total_area += thermal_boundary.opaque_area - for thermal_opening in thermal_boundary.thermal_openings: - total_area += thermal_opening.area - - view_factors_matrix = [] - for thermal_boundary_1 in thermal_zone.thermal_boundaries: - values = [] - for thermal_boundary_2 in thermal_zone.thermal_boundaries: - value = 0 - if thermal_boundary_1.id != thermal_boundary_2.id: - value = thermal_boundary_2.opaque_area / (total_area - thermal_boundary_1.opaque_area) - values.append(value) - for thermal_boundary in thermal_zone.thermal_boundaries: - for thermal_opening in thermal_boundary.thermal_openings: - value = thermal_opening.area / (total_area - thermal_boundary_1.opaque_area) - values.append(value) - view_factors_matrix.append(values) - - for thermal_boundary_1 in thermal_zone.thermal_boundaries: - values = [] - for thermal_opening_1 in thermal_boundary_1.thermal_openings: - for thermal_boundary_2 in thermal_zone.thermal_boundaries: - value = thermal_boundary_2.opaque_area / (total_area - thermal_opening_1.area) - values.append(value) - for thermal_boundary in thermal_zone.thermal_boundaries: - for thermal_opening_2 in thermal_boundary.thermal_openings: - value = 0 - if thermal_opening_1.id != thermal_opening_2.id: - value = thermal_opening_2.area / (total_area - thermal_opening_1.area) - values.append(value) - view_factors_matrix.append(values) - thermal_zone.view_factors_matrix = view_factors_matrix - - @staticmethod - def _create_storeys(building, archetype, divide_in_storeys): - building.average_storey_height = archetype.average_storey_height - building.storeys_above_ground = 1 - thermal_zones = StoreysGeneration(building, building.internal_zones[0], - divide_in_storeys=divide_in_storeys).thermal_zones - building.internal_zones[0].thermal_zones = thermal_zones - - def enrich_buildings(self): - """ - Raise not implemented error - """ - raise NotImplementedError diff --git a/imports/construction/us_physics_parameters.py b/imports/construction/nrel_physics_parameters.py similarity index 74% rename from imports/construction/us_physics_parameters.py rename to imports/construction/nrel_physics_parameters.py index cee5840c..22df677f 100644 --- a/imports/construction/us_physics_parameters.py +++ b/imports/construction/nrel_physics_parameters.py @@ -1,5 +1,5 @@ """ -UsPhysicsParameters import the construction and material information for US +NrelPhysicsParameters import the construction and material information defined by NREL SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2022 Concordia CERC group Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca @@ -7,23 +7,22 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord """ import sys -from imports.construction.nrel_physics_interface import NrelPhysicsInterface from catalog_factories.construction_catalog_factory import ConstructionCatalogFactory from city_model_structure.building_demand.layer import Layer from city_model_structure.building_demand.material import Material from imports.construction.helpers.construction_helper import ConstructionHelper +from imports.construction.helpers.storeys_generation import StoreysGeneration -class UsPhysicsParameters(NrelPhysicsInterface): +class NrelPhysicsParameters: """ - UsPhysicsParameters class + NrelPhysicsParameters class """ def __init__(self, city, base_path, divide_in_storeys=False): self._city = city self._path = base_path self._divide_in_storeys = divide_in_storeys self._climate_zone = ConstructionHelper.city_to_nrel_climate_zone(city.name) - super().__init__() def enrich_buildings(self): """ @@ -136,3 +135,53 @@ class UsPhysicsParameters(NrelPhysicsInterface): thermal_opening.frame_ratio = window_archetype.frame_ratio thermal_opening.g_value = window_archetype.g_value thermal_opening.overall_u_value = window_archetype.overall_u_value + + # todo: verify windows + @staticmethod + def _calculate_view_factors(thermal_zone): + """ + Get thermal zone view factors matrix + :return: [[float]] + """ + total_area = 0 + for thermal_boundary in thermal_zone.thermal_boundaries: + total_area += thermal_boundary.opaque_area + for thermal_opening in thermal_boundary.thermal_openings: + total_area += thermal_opening.area + + view_factors_matrix = [] + for thermal_boundary_1 in thermal_zone.thermal_boundaries: + values = [] + for thermal_boundary_2 in thermal_zone.thermal_boundaries: + value = 0 + if thermal_boundary_1.id != thermal_boundary_2.id: + value = thermal_boundary_2.opaque_area / (total_area - thermal_boundary_1.opaque_area) + values.append(value) + for thermal_boundary in thermal_zone.thermal_boundaries: + for thermal_opening in thermal_boundary.thermal_openings: + value = thermal_opening.area / (total_area - thermal_boundary_1.opaque_area) + values.append(value) + view_factors_matrix.append(values) + + for thermal_boundary_1 in thermal_zone.thermal_boundaries: + values = [] + for thermal_opening_1 in thermal_boundary_1.thermal_openings: + for thermal_boundary_2 in thermal_zone.thermal_boundaries: + value = thermal_boundary_2.opaque_area / (total_area - thermal_opening_1.area) + values.append(value) + for thermal_boundary in thermal_zone.thermal_boundaries: + for thermal_opening_2 in thermal_boundary.thermal_openings: + value = 0 + if thermal_opening_1.id != thermal_opening_2.id: + value = thermal_opening_2.area / (total_area - thermal_opening_1.area) + values.append(value) + view_factors_matrix.append(values) + thermal_zone.view_factors_matrix = view_factors_matrix + + @staticmethod + def _create_storeys(building, archetype, divide_in_storeys): + building.average_storey_height = archetype.average_storey_height + building.storeys_above_ground = 1 + thermal_zones = StoreysGeneration(building, building.internal_zones[0], + divide_in_storeys=divide_in_storeys).thermal_zones + building.internal_zones[0].thermal_zones = thermal_zones diff --git a/imports/construction_factory.py b/imports/construction_factory.py index 7f136ed0..acf35988 100644 --- a/imports/construction_factory.py +++ b/imports/construction_factory.py @@ -5,7 +5,7 @@ Copyright © 2022 Concordia CERC group Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca """ from pathlib import Path -from imports.construction.us_physics_parameters import UsPhysicsParameters +from imports.construction.nrel_physics_parameters import NrelPhysicsParameters class ConstructionFactory: @@ -23,7 +23,7 @@ class ConstructionFactory: """ Enrich the city by using NREL information """ - UsPhysicsParameters(self._city, self._base_path).enrich_buildings() + NrelPhysicsParameters(self._city, self._base_path).enrich_buildings() self._city.level_of_detail.construction = 2 def enrich(self): @@ -38,4 +38,4 @@ class ConstructionFactory: Enrich the city given to the class using the class given handler :return: None """ - UsPhysicsParameters(self._city, self._base_path).enrich_buildings() \ No newline at end of file + NrelPhysicsParameters(self._city, self._base_path).enrich_buildings() diff --git a/imports/usage/ca_usage_parameters.py b/imports/usage/ca_usage_parameters.py deleted file mode 100644 index cc5c4f41..00000000 --- a/imports/usage/ca_usage_parameters.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -CaUsageParameters model the usage properties -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Concordia CERC group -Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca -""" -import sys - -from imports.geometry.helpers.geometry_helper import GeometryHelper -from imports.usage.hft_usage_interface import HftUsageInterface -from imports.usage.helpers.usage_helper import UsageHelper - - -class HftUsageParameters(HftUsageInterface): - """ - CaUsageParameters class - """ - def __init__(self, city, base_path): - super().__init__(base_path, 'ca_archetypes_reduced.xml') - self._city = city - - def enrich_buildings(self): - """ - Returns the city with the usage parameters assigned to the buildings - :return: - """ - city = self._city - for building in city.buildings: - usage = GeometryHelper().libs_usage_from_libs_function(building.function) - try: - archetype = self._search_archetype(usage) - except KeyError: - sys.stderr.write(f'Building {building.name} has unknown archetype for building function:' - f' {building.function}, that assigns building usage as ' - f'{GeometryHelper().libs_usage_from_libs_function(building.function)}\n') - return - - for internal_zone in building.internal_zones: - usage_zone = self._assign_values(building.function, archetype) - usage_zone.percentage = 1 - internal_zone.usage_zones = [usage_zone] diff --git a/imports/usage/comnet_usage_parameters.py b/imports/usage/comnet_usage_parameters.py index c1cf1117..b2265fe1 100644 --- a/imports/usage/comnet_usage_parameters.py +++ b/imports/usage/comnet_usage_parameters.py @@ -15,7 +15,7 @@ from helpers.configuration_helper import ConfigurationHelper as ch from imports.geometry.helpers.geometry_helper import GeometryHelper from imports.usage.helpers.usage_helper import UsageHelper from imports.usage.helpers.schedules_helper import SchedulesHelper -from city_model_structure.building_demand.usage_zone import UsageZone +from city_model_structure.building_demand.usage import Usage from city_model_structure.building_demand.lighting import Lighting from city_model_structure.building_demand.occupancy import Occupancy from city_model_structure.building_demand.appliances import Appliances @@ -74,7 +74,7 @@ class ComnetUsageParameters: @staticmethod def _parse_usage_type(comnet_usage, data, schedules_data): - _usage_zone = UsageZone() + _usage = Usage() # lighting _lighting = Lighting() @@ -105,7 +105,7 @@ class ComnetUsageParameters: * ch().comnet_occupancy_sensible_radiant _occupancy.latent_internal_gain = data['occupancy'][comnet_usage][2] - _usage_zone.mechanical_air_change = data['ventilation rate'][comnet_usage][0] + _usage.mechanical_air_change = data['ventilation rate'][comnet_usage][0] schedules_usage = UsageHelper.schedules_key(data['schedules_key'][comnet_usage][0]) @@ -158,9 +158,9 @@ class ComnetUsageParameters: _schedules.append(schedules[schedules_types['Receptacle']+pointer]) _appliances.schedules = _schedules - _usage_zone.occupancy = _occupancy - _usage_zone.lighting = _lighting - _usage_zone.appliances = _appliances + _usage.occupancy = _occupancy + _usage.lighting = _lighting + _usage.appliances = _appliances _control = ThermalControl() _schedules = [] @@ -175,9 +175,9 @@ class ComnetUsageParameters: for pointer in range(0, 3): _schedules.append(schedules[schedules_types['HVAC Avail']+pointer]) _control.hvac_availability_schedules = _schedules - _usage_zone.thermal_control = _control + _usage.thermal_control = _control - return _usage_zone + return _usage def _search_archetypes(self, libs_usage): for item in self._data['lighting']: @@ -213,13 +213,13 @@ class ComnetUsageParameters: if internal_zone.volume <= 0: raise Exception('Internal zone volume is zero, ACH cannot be calculated') volume_per_area = internal_zone.volume / internal_zone.area - usage_zone = UsageZone() - usage_zone.usage = usage + usage_zone = Usage() + usage_zone.name = usage self._assign_values_usage_zone(usage_zone, archetype_usage, volume_per_area) usage_zone.percentage = 1 self._calculate_reduced_values_from_extended_library(usage_zone, archetype_usage) - internal_zone.usage_zones = [usage_zone] + internal_zone.usages = [usage_zone] @staticmethod def _assign_values_usage_zone(usage_zone, archetype, volume_per_area): diff --git a/imports/usage/hft_usage_parameters.py b/imports/usage/hft_usage_parameters.py index afe7e300..3d869242 100644 --- a/imports/usage/hft_usage_parameters.py +++ b/imports/usage/hft_usage_parameters.py @@ -39,4 +39,4 @@ class HftUsageParameters(HftUsageInterface): libs_usage = GeometryHelper().libs_usage_from_libs_function(building.function) usage_zone = self._assign_values(UsageHelper().hft_from_libs_usage(libs_usage), archetype) usage_zone.percentage = 1 - internal_zone.usage_zones = [usage_zone] + internal_zone.usages = [usage_zone] diff --git a/imports/usage/nrcan_usage_parameters.py b/imports/usage/nrcan_usage_parameters.py deleted file mode 100644 index 19034827..00000000 --- a/imports/usage/nrcan_usage_parameters.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -NrcanUsageParameters imports the usage information for Canada and feeds the central data model classes with it -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Concordia CERC group -Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca -""" - -from catalog_factories.usage_catalog_factory import UsageCatalogFactory - -class NrcanUsageParameters: - """ - NrcanUsageParameters class - """ - @staticmethod - def _search_archetype(usage_name, year_of_construction, climate_zone): - nrcan_catalog = UsageCatalogFactory('nrcan').catalog - nrcan_archetypes = nrcan_catalog.entries('archetypes') - for building_archetype in nrcan_archetypes: - - return None - - @staticmethod - def _search_usage_in_archetype(archetype, usage_name): - usage_archetypes = archetype. - for usage_archetype in archetypes_archetypes: - if str(usage_name) == str(usage_archetype.type): - return usage_archetype - return None - - def _assign_values(self, usage, archetype): - for thermal_zone in thermal_zones: - thermal_zone.additional_thermal_bridge_u_value = archetype.extra_loses_due_to_thermal_bridges - - def enrich_buildings(self): - """ - Raise not implemented error - """ - raise NotImplementedError diff --git a/imports/usage_factory.py b/imports/usage_factory.py index 50d94915..3ec4e45d 100644 --- a/imports/usage_factory.py +++ b/imports/usage_factory.py @@ -27,14 +27,14 @@ class UsageFactory: Enrich the city with HFT usage library """ self._city.level_of_detail.usage = 2 - return HftUsageParameters(self._city, self._base_path).enrich_buildings() + HftUsageParameters(self._city, self._base_path).enrich_buildings() def _comnet(self): """ Enrich the city with COMNET usage library """ self._city.level_of_detail.usage = 2 - return ComnetUsageParameters(self._city, self._base_path).enrich_buildings() + ComnetUsageParameters(self._city, self._base_path).enrich_buildings() def enrich(self): """ diff --git a/unittests/test_construction_factory.py b/unittests/test_construction_factory.py index 075abf72..6ba75ee9 100644 --- a/unittests/test_construction_factory.py +++ b/unittests/test_construction_factory.py @@ -122,7 +122,7 @@ class TestConstructionFactory(TestCase): self.assertIsNone(thermal_zone.ordinate_number, 'thermal_zone ordinate number is not none') self.assertIsNotNone(thermal_zone.view_factors_matrix, 'thermal_zone view factors matrix is none') self.assertIsNotNone(thermal_zone.total_floor_area, 'thermal zone total_floor_area is none') - self.assertIsNone(thermal_zone.name, 'thermal_zone usage is not none') + self.assertIsNone(thermal_zone.usage, 'thermal_zone usage is not none') self.assertIsNone(thermal_zone.hours_day, 'thermal_zone hours a day is not none') self.assertIsNone(thermal_zone.days_year, 'thermal_zone days a year is not none') self.assertIsNone(thermal_zone.mechanical_air_change, 'thermal_zone mechanical air change is not none') diff --git a/unittests/test_enrichement.py b/unittests/test_enrichement.py index e1c7b7d7..1e7fc6d3 100644 --- a/unittests/test_enrichement.py +++ b/unittests/test_enrichement.py @@ -35,8 +35,8 @@ class TestGeometryFactory(TestCase): self._check_buildings(city) for building in city.buildings: for internal_zone in building.internal_zones: - self.assertIsNot(len(internal_zone.usage_zones), 0, 'no building usage_zones defined') - for usage_zone in internal_zone.usage_zones: + self.assertIsNot(len(internal_zone.usages), 0, 'no building usage_zones defined') + for usage_zone in internal_zone.usages: self.assertIsNotNone(usage_zone.id, 'usage id is none') for thermal_zone in internal_zone.thermal_zones: self._check_thermal_zone(thermal_zone) @@ -45,7 +45,7 @@ class TestGeometryFactory(TestCase): for building in city.buildings: self.assertIsNotNone(building.internal_zones, 'no internal zones created') for internal_zone in building.internal_zones: - self.assertIsNotNone(internal_zone.usage_zones, 'usage zones are not defined') + self.assertIsNotNone(internal_zone.usages, 'usage zones are not defined') self.assertIsNotNone(internal_zone.thermal_zones, 'thermal zones are not defined') self.assertIsNone(building.basement_heated, 'building basement_heated is not none') self.assertIsNone(building.attic_heated, 'building attic_heated is not none') @@ -55,7 +55,7 @@ class TestGeometryFactory(TestCase): def _check_thermal_zone(self, thermal_zone): self.assertIsNotNone(thermal_zone.id, 'thermal_zone id is none') - self.assertIsNotNone(thermal_zone.name, 'thermal_zone usage is not none') + self.assertIsNotNone(thermal_zone.usage, 'thermal_zone usage is not none') self.assertIsNotNone(thermal_zone.hours_day, 'thermal_zone hours a day is none') self.assertIsNotNone(thermal_zone.days_year, 'thermal_zone days a year is none') self.assertIsNotNone(thermal_zone.occupancy, 'thermal_zone occupancy is none') diff --git a/unittests/test_geometry_factory.py b/unittests/test_geometry_factory.py index 5da32682..e6e61355 100644 --- a/unittests/test_geometry_factory.py +++ b/unittests/test_geometry_factory.py @@ -59,7 +59,7 @@ class TestGeometryFactory(TestCase): self.assertIsNotNone(building.roofs, 'building roofs is none') self.assertIsNotNone(building.internal_zones, 'building internal zones is none') for internal_zone in building.internal_zones: - self.assertIsNone(internal_zone.usage_zones, 'usage zones are defined') + self.assertIsNone(internal_zone.usages, 'usage zones are defined') self.assertIsNone(internal_zone.thermal_zones, 'thermal zones are defined') self.assertIsNone(building.basement_heated, 'building basement_heated is not none') self.assertIsNone(building.attic_heated, 'building attic_heated is not none') diff --git a/unittests/test_insel_exports.py b/unittests/test_insel_exports.py index bc6b2776..ae5bf283 100644 --- a/unittests/test_insel_exports.py +++ b/unittests/test_insel_exports.py @@ -133,13 +133,13 @@ class TestExports(TestCase): if thermal_boundary.type is not cte.GROUND: self.assertIsNotNone(thermal_boundary.parent_surface.short_wave_reflectance) - for usage_zone in internal_zone.usage_zones: - self.assertIsNotNone(usage_zone.percentage, f'usage zone {usage_zone.usage} percentage is none') - self.assertIsNotNone(usage_zone.internal_gains, f'usage zone {usage_zone.usage} internal_gains is none') - self.assertIsNotNone(usage_zone.thermal_control, f'usage zone {usage_zone.usage} thermal_control is none') - self.assertIsNotNone(usage_zone.hours_day, f'usage zone {usage_zone.usage} hours_day is none') - self.assertIsNotNone(usage_zone.days_year, f'usage zone {usage_zone.usage} days_year is none') - self.assertIsNotNone(usage_zone.mechanical_air_change, f'usage zone {usage_zone.usage} ' + for usage_zone in internal_zone.usages: + self.assertIsNotNone(usage_zone.percentage, f'usage zone {usage_zone.name} percentage is none') + self.assertIsNotNone(usage_zone.internal_gains, f'usage zone {usage_zone.name} internal_gains is none') + self.assertIsNotNone(usage_zone.thermal_control, f'usage zone {usage_zone.name} thermal_control is none') + self.assertIsNotNone(usage_zone.hours_day, f'usage zone {usage_zone.name} hours_day is none') + self.assertIsNotNone(usage_zone.days_year, f'usage zone {usage_zone.name} days_year is none') + self.assertIsNotNone(usage_zone.mechanical_air_change, f'usage zone {usage_zone.name} ' f'mechanical_air_change is none') # export files try: diff --git a/unittests/test_usage_factory.py b/unittests/test_usage_factory.py index 1e4202ba..1a593493 100644 --- a/unittests/test_usage_factory.py +++ b/unittests/test_usage_factory.py @@ -51,7 +51,7 @@ class TestUsageFactory(TestCase): self.assertIsNotNone(building.walls, 'building walls is none') self.assertIsNotNone(building.roofs, 'building roofs is none') for internal_zone in building.internal_zones: - self.assertTrue(len(internal_zone.usage_zones) > 0, 'usage zones are not defined') + self.assertTrue(len(internal_zone.usages) > 0, 'usage zones are not defined') self.assertIsNone(internal_zone.thermal_zones, 'thermal zones are defined') self.assertIsNone(building.basement_heated, 'building basement_heated is not none') self.assertIsNone(building.attic_heated, 'building attic_heated is not none') @@ -91,8 +91,8 @@ class TestUsageFactory(TestCase): self._check_buildings(city) for building in city.buildings: for internal_zone in building.internal_zones: - self.assertIsNot(len(internal_zone.usage_zones), 0, 'no building usage_zones defined') - for usage_zone in internal_zone.usage_zones: + self.assertIsNot(len(internal_zone.usages), 0, 'no building usage_zones defined') + for usage_zone in internal_zone.usages: self._check_usage_zone(usage_zone) self.assertIsNotNone(usage_zone.mechanical_air_change, 'mechanical air change is none') self.assertIsNotNone(usage_zone.thermal_control.heating_set_point_schedules, @@ -139,8 +139,8 @@ class TestUsageFactory(TestCase): self._check_buildings(city) for building in city.buildings: for internal_zone in building.internal_zones: - self.assertIsNot(len(internal_zone.usage_zones), 0, 'no building usage_zones defined') - for usage_zone in internal_zone.usage_zones: + self.assertIsNot(len(internal_zone.usages), 0, 'no building usage_zones defined') + for usage_zone in internal_zone.usages: self._check_usage_zone(usage_zone) self.assertIsNone(usage_zone.mechanical_air_change, 'mechanical air change is not none') self.assertIsNotNone(usage_zone.thermal_control.heating_set_point_schedules, From b34b07b161285f93f58d43f0d34433f9e55cd39d Mon Sep 17 00:00:00 2001 From: Pilar Date: Wed, 7 Dec 2022 10:54:28 -0500 Subject: [PATCH 3/8] added nrcan importer usage importer now reads from catalogs --- catalog_factories/data_models/usages/usage.py | 8 +- catalog_factories/usage/nrcan_catalog.py | 18 +- .../building_demand/thermal_zone.py | 54 +++- exports/building_energy/idf.py | 28 +- .../construction/nrel_physics_parameters.py | 11 +- imports/usage/comnet_usage_parameters.py | 215 ++------------ imports/usage/helpers/usage_helper.py | 42 ++- imports/usage/hft_usage_interface.py | 280 ------------------ imports/usage/hft_usage_parameters.py | 42 --- imports/usage/nrcan_usage_parameters.py | 191 ++++++++++++ imports/usage_factory.py | 18 +- unittests/test_construction_factory.py | 2 +- unittests/test_enrichement.py | 4 +- 13 files changed, 341 insertions(+), 572 deletions(-) delete mode 100644 imports/usage/hft_usage_interface.py delete mode 100644 imports/usage/hft_usage_parameters.py create mode 100644 imports/usage/nrcan_usage_parameters.py diff --git a/catalog_factories/data_models/usages/usage.py b/catalog_factories/data_models/usages/usage.py index e83178b8..dc2d7478 100644 --- a/catalog_factories/data_models/usages/usage.py +++ b/catalog_factories/data_models/usages/usage.py @@ -22,7 +22,7 @@ class Usage: lighting, appliances, thermal_control): - self._usage = usage + self._name = usage self._hours_day = hours_day self._days_year = days_year self._mechanical_air_change = mechanical_air_change @@ -34,12 +34,12 @@ class Usage: self._thermal_control = thermal_control @property - def usage(self) -> Union[None, str]: + def name(self) -> Union[None, str]: """ - Get usage zone usage + Get usage zone usage name :return: None or str """ - return self._usage + return self._name @property def hours_day(self) -> Union[None, float]: diff --git a/catalog_factories/usage/nrcan_catalog.py b/catalog_factories/usage/nrcan_catalog.py index 949cb3d2..5842bc3f 100644 --- a/catalog_factories/usage/nrcan_catalog.py +++ b/catalog_factories/usage/nrcan_catalog.py @@ -32,10 +32,6 @@ class NrcanCatalog(Catalog): self._load_schedules() self._content = Content(self._load_archetypes()) - def _calculate_hours_day(self, function): - # todo: pilar need to check how to calculate this value - return 24 - @staticmethod def _extract_schedule(raw): nrcan_schedule_type = raw['category'] @@ -69,8 +65,8 @@ class NrcanCatalog(Catalog): def _load_archetypes(self): usages = [] - usage = self._metadata['nrcan']['standards']['usage'] - url = f'{self._base_url}{usage["space_types_location"]}' + name = self._metadata['nrcan']['standards']['usage'] + url = f'{self._base_url}{name["space_types_location"]}' with urllib.request.urlopen(url) as json_file: space_types = json.load(json_file)['tables']['space_types']['table'] space_types = [st for st in space_types if st['building_type'] == 'Space Function'] @@ -80,8 +76,6 @@ class NrcanCatalog(Catalog): ventilation_rate = space_type['ventilation_per_area'] if ventilation_rate == 0: ventilation_rate = space_type['ventilation_per_person'] - hours_day = self._calculate_hours_day(usage_type) - days_year = 365 occupancy_schedule_name = space_type['occupancy_schedule'] lighting_schedule_name = space_type['lighting_schedule'] appliance_schedule_name = space_type['electric_equipment_schedule'] @@ -97,11 +91,13 @@ class NrcanCatalog(Catalog): occupancy_density = space_type['occupancy_per_area'] lighting_density = space_type['lighting_per_area'] lighting_radiative_fraction = space_type['lighting_fraction_radiant'] + lighting_convective_fraction = 0 if lighting_radiative_fraction is not None: lighting_convective_fraction = 1 - lighting_radiative_fraction lighting_latent_fraction = 0 appliances_density = space_type['electric_equipment_per_area'] appliances_radiative_fraction = space_type['electric_equipment_fraction_radiant'] + appliances_convective_fraction = 0 if appliances_radiative_fraction is not None: appliances_convective_fraction = 1 - appliances_radiative_fraction appliances_latent_fraction = space_type['electric_equipment_fraction_latent'] @@ -131,6 +127,8 @@ class NrcanCatalog(Catalog): None, None, None) + hours_day = None + days_year = None usages.append(Usage(usage_type, hours_day, days_year, @@ -149,7 +147,7 @@ class NrcanCatalog(Catalog): """ _names = {'usages': []} for usage in self._content.usages: - _names['usages'].append(usage.usage) + _names['usages'].append(usage.name) return _names def entries(self, category=None): @@ -165,6 +163,6 @@ class NrcanCatalog(Catalog): :parm: entry name """ for usage in self._content.usages: - if usage.usage.lower() == name.lower(): + if usage.name.lower() == name.lower(): return usage raise IndexError(f"{name} doesn't exists in the catalog") diff --git a/city_model_structure/building_demand/thermal_zone.py b/city_model_structure/building_demand/thermal_zone.py index c09b8acf..57a3f32a 100644 --- a/city_model_structure/building_demand/thermal_zone.py +++ b/city_model_structure/building_demand/thermal_zone.py @@ -26,7 +26,7 @@ class ThermalZone: """ ThermalZone class """ - def __init__(self, thermal_boundaries, parent_internal_zone, volume, footprint_area, usage=None): + def __init__(self, thermal_boundaries, parent_internal_zone, volume, footprint_area, usage_name=None): self._id = None self._parent_internal_zone = parent_internal_zone self._footprint_area = footprint_area @@ -40,9 +40,9 @@ class ThermalZone: self._ordinate_number = None self._view_factors_matrix = None self._total_floor_area = None - self._usage = usage + self._usage_name = usage_name self._usage_from_parent = False - if usage is None: + if usage_name is None: self._usage_from_parent = True self._hours_day = None self._days_year = None @@ -60,14 +60,14 @@ class ThermalZone: if self._usage_from_parent: self._usages = copy.deepcopy(self._parent_internal_zone.usages) else: - values = self._usage.split('_') + values = self._usage_name.split('_') usages = [] for value in values: usages.append(value.split('-')) self._usages = [] for parent_usage in self._parent_internal_zone.usages: for value in usages: - if parent_usage.usage == value[1]: + if parent_usage.name == value[1]: new_usage = copy.deepcopy(parent_usage) new_usage.percentage = float(value[0])/100 self._usages.append(new_usage) @@ -224,19 +224,19 @@ class ThermalZone: self._view_factors_matrix = value @property - def usage(self) -> Union[None, str]: + def usage_name(self) -> Union[None, str]: """ - Get thermal zone usage + Get thermal zone usage name :return: None or str """ if self._usage_from_parent: if self._parent_internal_zone.usages is None: return None - self._usage = '' + self._usage_name = '' for usage_zone in self._parent_internal_zone.usages: - self._usage += str(round(usage_zone.percentage * 100)) + '-' + usage_zone.name + '_' - self._usage = self._usage[:-1] - return self._usage + self._usage_name += str(round(usage_zone.percentage * 100)) + '-' + usage_zone.name + '_' + self._usage_name = self._usage_name[:-1] + return self._usage_name @staticmethod def _get_schedule_of_day(requested_day_type, schedules): @@ -322,7 +322,13 @@ class ThermalZone: if _occupancy_reference.occupancy_schedules is not None: _schedules = [] for i_schedule in range(0, len(_occupancy_reference.occupancy_schedules)): - schedule = copy.deepcopy(_occupancy_reference.occupancy_schedules[i_schedule]) + schedule = Schedule() + schedule.type = _occupancy_reference.occupancy_schedules[i_schedule].type + schedule.day_types = _occupancy_reference.occupancy_schedules[i_schedule].day_types + schedule.data_type = _occupancy_reference.occupancy_schedules[i_schedule].data_type + schedule.time_step = _occupancy_reference.occupancy_schedules[i_schedule].time_step + schedule.time_range = _occupancy_reference.occupancy_schedules[i_schedule].time_range + new_values = [] for i_value in range(0, len(_occupancy_reference.occupancy_schedules[i_schedule].values)): _new_value = 0 @@ -374,7 +380,13 @@ class ThermalZone: if _lighting_reference.schedules is not None: _schedules = [] for i_schedule in range(0, len(_lighting_reference.schedules)): - schedule = copy.deepcopy(_lighting_reference.schedules[i_schedule]) + schedule = Schedule() + schedule.type = _lighting_reference.schedules[i_schedule].type + schedule.day_types = _lighting_reference.schedules[i_schedule].day_types + schedule.data_type = _lighting_reference.schedules[i_schedule].data_type + schedule.time_step = _lighting_reference.schedules[i_schedule].time_step + schedule.time_range = _lighting_reference.schedules[i_schedule].time_range + new_values = [] for i_value in range(0, len(_lighting_reference.schedules[i_schedule].values)): _new_value = 0 @@ -426,7 +438,13 @@ class ThermalZone: if _appliances_reference.schedules is not None: _schedules = [] for i_schedule in range(0, len(_appliances_reference.schedules)): - schedule = copy.deepcopy(_appliances_reference.schedules[i_schedule]) + schedule = Schedule() + schedule.type = _appliances_reference.schedules[i_schedule].type + schedule.day_types = _appliances_reference.schedules[i_schedule].day_types + schedule.data_type = _appliances_reference.schedules[i_schedule].data_type + schedule.time_step = _appliances_reference.schedules[i_schedule].time_step + schedule.time_range = _appliances_reference.schedules[i_schedule].time_range + new_values = [] for i_value in range(0, len(_appliances_reference.schedules[i_schedule].values)): _new_value = 0 @@ -535,7 +553,13 @@ class ThermalZone: _schedules = [] _schedule_type = _types_reference[i_type][1] for i_schedule in range(0, len(_schedule_type)): - schedule = copy.deepcopy(_schedule_type[i_schedule]) + schedule = Schedule() + schedule.type = _schedule_type[i_schedule].type + schedule.day_types = _schedule_type[i_schedule].day_types + schedule.data_type = _schedule_type[i_schedule].data_type + schedule.time_step = _schedule_type[i_schedule].time_step + schedule.time_range = _schedule_type[i_schedule].time_range + new_values = [] for i_value in range(0, len(_schedule_type[i_schedule].values)): _new_value = 0 diff --git a/exports/building_energy/idf.py b/exports/building_energy/idf.py index 43fa23d0..ac4ef398 100644 --- a/exports/building_energy/idf.py +++ b/exports/building_energy/idf.py @@ -207,9 +207,9 @@ class Idf: _schedule.values = _infiltration_values _infiltration_schedules.append(_schedule) for schedule in self._idf.idfobjects[self._HOURLY_SCHEDULE]: - if schedule.Name == f'Infiltration schedules {thermal_zone.usage}': + if schedule.Name == f'Infiltration schedules {thermal_zone.usage_name}': return - return self._add_standard_compact_hourly_schedule(thermal_zone.usage, 'Infiltration', _infiltration_schedules) + return self._add_standard_compact_hourly_schedule(thermal_zone.usage_name, 'Infiltration', _infiltration_schedules) def _add_people_activity_level_schedules(self, thermal_zone): _occ = thermal_zone.occupancy @@ -219,9 +219,9 @@ class Idf: _total_heat = (_occ.sensible_convective_internal_gain + _occ.sensible_radiative_internal_gain + _occ.latent_internal_gain) / _occ.occupancy_density for schedule in self._idf.idfobjects[self._COMPACT_SCHEDULE]: - if schedule.Name == f'Activity Level schedules {thermal_zone.usage}': + if schedule.Name == f'Activity Level schedules {thermal_zone.usage_name}': return - _kwargs = {'Name': f'Activity Level schedules {thermal_zone.usage}', + _kwargs = {'Name': f'Activity Level schedules {thermal_zone.usage_name}', 'Schedule_Type_Limits_Name': self.idf_type_limits[cte.ANY_NUMBER], 'Field_1': 'Through: 12/31', 'Field_2': 'For AllDays', @@ -300,15 +300,15 @@ class Idf: self._add_heating_system(thermal_zone, name) def _add_thermostat(self, thermal_zone): - thermostat_name = f'Thermostat {thermal_zone.usage}' + thermostat_name = f'Thermostat {thermal_zone.usage_name}' for thermostat in self._idf.idfobjects[self._THERMOSTAT]: if thermostat.Name == thermostat_name: return thermostat # todo: change schedules to schedule name and create schedules using the add_schedule function return self._idf.newidfobject(self._THERMOSTAT, Name=thermostat_name, - Heating_Setpoint_Schedule_Name=f'Heating thermostat schedules {thermal_zone.usage}', - Cooling_Setpoint_Schedule_Name=f'Cooling thermostat schedules {thermal_zone.usage}') + Heating_Setpoint_Schedule_Name=f'Heating thermostat schedules {thermal_zone.usage_name}', + Cooling_Setpoint_Schedule_Name=f'Cooling thermostat schedules {thermal_zone.usage_name}') def _add_heating_system(self, thermal_zone, zone_name): for air_system in self._idf.idfobjects[self._IDEAL_LOAD_AIR_SYSTEM]: @@ -317,9 +317,9 @@ class Idf: thermostat = self._add_thermostat(thermal_zone) self._idf.newidfobject(self._IDEAL_LOAD_AIR_SYSTEM, Zone_Name=zone_name, - System_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage}', - Heating_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage}', - Cooling_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage}', + System_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage_name}', + Heating_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage_name}', + Cooling_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage_name}', Template_Thermostat_Name=thermostat.Name) def _add_occupancy(self, thermal_zone, zone_name): @@ -330,11 +330,11 @@ class Idf: self._idf.newidfobject(self._PEOPLE, Name=f'{zone_name}_occupancy', Zone_or_ZoneList_Name=zone_name, - Number_of_People_Schedule_Name=f'Occupancy schedules {thermal_zone.usage}', + Number_of_People_Schedule_Name=f'Occupancy schedules {thermal_zone.usage_name}', Number_of_People_Calculation_Method="People", Number_of_People=number_of_people, Fraction_Radiant=fraction_radiant, - Activity_Level_Schedule_Name=f'Activity Level schedules {thermal_zone.usage}' + Activity_Level_Schedule_Name=f'Activity Level schedules {thermal_zone.usage_name}' ) def _add_infiltration(self, thermal_zone, zone_name): @@ -344,7 +344,7 @@ class Idf: self._idf.newidfobject(self._INFILTRATION, Name=f'{zone_name}_infiltration', Zone_or_ZoneList_Name=zone_name, - Schedule_Name=f'Infiltration schedules {thermal_zone.usage}', + Schedule_Name=f'Infiltration schedules {thermal_zone.usage_name}', Design_Flow_Rate_Calculation_Method='AirChanges/Hour', Air_Changes_per_Hour=thermal_zone.mechanical_air_change ) @@ -387,7 +387,7 @@ class Idf: self._add_vegetation_material(thermal_boundary.parent_surface.vegetation) for thermal_opening in thermal_boundary.thermal_openings: self._add_window_construction_and_material(thermal_opening) - usage = thermal_zone.usage + usage = thermal_zone.usage_name if building.name in self._target_buildings or building.name in self._adjacent_buildings: self._add_infiltration_schedules(thermal_zone) self._add_schedules(usage, 'Occupancy', thermal_zone.occupancy.occupancy_schedules) diff --git a/imports/construction/nrel_physics_parameters.py b/imports/construction/nrel_physics_parameters.py index 22df677f..20576519 100644 --- a/imports/construction/nrel_physics_parameters.py +++ b/imports/construction/nrel_physics_parameters.py @@ -29,12 +29,14 @@ class NrelPhysicsParameters: Returns the city with the construction parameters assigned to the buildings """ city = self._city + nrel_catalog = ConstructionCatalogFactory('nrel').catalog for building in city.buildings: try: - archetype = self._search_archetype(building.function, building.year_of_construction, self._climate_zone) + archetype = self._search_archetype(nrel_catalog, building.function, building.year_of_construction, + self._climate_zone) except KeyError: - sys.stderr.write(f'Building {building.name} has unknown archetype for building function: {building.function} ' - f'and building year of construction: {building.year_of_construction} ' + sys.stderr.write(f'Building {building.name} has unknown construction archetype for building function: ' + f'{building.function} and building year of construction: {building.year_of_construction} ' f'and climate zone reference norm {self._climate_zone}\n') return @@ -62,8 +64,7 @@ class NrelPhysicsParameters: self._calculate_view_factors(thermal_zone) @staticmethod - def _search_archetype(function, year_of_construction, climate_zone): - nrel_catalog = ConstructionCatalogFactory('nrel').catalog + def _search_archetype(nrel_catalog, function, year_of_construction, climate_zone): nrel_archetypes = nrel_catalog.entries('archetypes') for building_archetype in nrel_archetypes: construction_period_limits = building_archetype.construction_period.split(' - ') diff --git a/imports/usage/comnet_usage_parameters.py b/imports/usage/comnet_usage_parameters.py index b2265fe1..c84e9c32 100644 --- a/imports/usage/comnet_usage_parameters.py +++ b/imports/usage/comnet_usage_parameters.py @@ -1,20 +1,15 @@ """ -ComnetUsageParameters model the usage properties +ComnetUsageParameters extracts the usage properties from Comnet catalog and assigns to each building SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2022 Concordia CERC group Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca """ import copy import sys -from typing import Dict -import pandas as pd import numpy import helpers.constants as cte -from helpers.configuration_helper import ConfigurationHelper as ch -from imports.geometry.helpers.geometry_helper import GeometryHelper from imports.usage.helpers.usage_helper import UsageHelper -from imports.usage.helpers.schedules_helper import SchedulesHelper from city_model_structure.building_demand.usage import Usage from city_model_structure.building_demand.lighting import Lighting from city_model_structure.building_demand.occupancy import Occupancy @@ -22,6 +17,7 @@ from city_model_structure.building_demand.appliances import Appliances from city_model_structure.building_demand.thermal_control import ThermalControl from city_model_structure.attributes.schedule import Schedule from city_model_structure.building_demand.internal_gain import InternalGain +from catalog_factories.usage_catalog_factory import UsageCatalogFactory class ComnetUsageParameters: @@ -30,162 +26,7 @@ class ComnetUsageParameters: """ def __init__(self, city, base_path): self._city = city - self._base_path = str(base_path / 'comnet_archetypes.xlsx') - self._data = self._read_file() - self._comnet_schedules_path = str(base_path / 'comnet_schedules_archetypes.xlsx') - self._xls = pd.ExcelFile(self._comnet_schedules_path) - - def _read_file(self) -> Dict: - """ - reads xlsx files containing usage information into a dictionary - :return : Dict - """ - number_usage_types = 33 - xl_file = pd.ExcelFile(self._base_path) - file_data = pd.read_excel(xl_file, sheet_name="Modeling Data", usecols="A:AB", skiprows=[0, 1, 2], - nrows=number_usage_types) - - lighting_data = {} - plug_loads_data = {} - occupancy_data = {} - ventilation_rate = {} - water_heating = {} - process_data = {} - schedules_key = {} - - for j in range(0, number_usage_types): - usage_parameters = file_data.iloc[j] - usage_type = usage_parameters[0] - lighting_data[usage_type] = usage_parameters[1:6].values.tolist() - plug_loads_data[usage_type] = usage_parameters[8:13].values.tolist() - occupancy_data[usage_type] = usage_parameters[17:20].values.tolist() - ventilation_rate[usage_type] = usage_parameters[20:21].values.tolist() - water_heating[usage_type] = usage_parameters[23:24].values.tolist() - process_data[usage_type] = usage_parameters[24:26].values.tolist() - schedules_key[usage_type] = usage_parameters[27:28].values.tolist() - - return {'lighting': lighting_data, - 'plug loads': plug_loads_data, - 'occupancy': occupancy_data, - 'ventilation rate': ventilation_rate, - 'water heating': water_heating, - 'process': process_data, - 'schedules_key': schedules_key} - - @staticmethod - def _parse_usage_type(comnet_usage, data, schedules_data): - _usage = Usage() - - # lighting - _lighting = Lighting() - _lighting.latent_fraction = ch().comnet_lighting_latent - _lighting.convective_fraction = ch().comnet_lighting_convective - _lighting.radiative_fraction = ch().comnet_lighting_radiant - _lighting.density = data['lighting'][comnet_usage][4] - - # plug loads - _appliances = None - if data['plug loads'][comnet_usage][0] != 'n.a.': - _appliances = Appliances() - _appliances.latent_fraction = ch().comnet_plugs_latent - _appliances.convective_fraction = ch().comnet_plugs_convective - _appliances.radiative_fraction = ch().comnet_plugs_radiant - _appliances.density = data['plug loads'][comnet_usage][0] - - # occupancy - _occupancy = Occupancy() - value = data['occupancy'][comnet_usage][0] - _occupancy.occupancy_density = 0 - if value != 0: - _occupancy.occupancy_density = 1 / value - - _occupancy.sensible_convective_internal_gain = data['occupancy'][comnet_usage][1] \ - * ch().comnet_occupancy_sensible_convective - _occupancy.sensible_radiative_internal_gain = data['occupancy'][comnet_usage][1] \ - * ch().comnet_occupancy_sensible_radiant - _occupancy.latent_internal_gain = data['occupancy'][comnet_usage][2] - - _usage.mechanical_air_change = data['ventilation rate'][comnet_usage][0] - - schedules_usage = UsageHelper.schedules_key(data['schedules_key'][comnet_usage][0]) - - _extracted_data = pd.read_excel(schedules_data, sheet_name=schedules_usage, usecols="A:AA", skiprows=[0, 1, 2, 3], - nrows=39) - schedules = [] - number_of_schedule_types = 13 - schedules_per_schedule_type = 3 - day_types = dict({'week_day': 0, 'saturday': 1, 'sunday': 2}) - for schedule_types in range(0, number_of_schedule_types): - name = '' - data_type = '' - for schedule_day in range(0, schedules_per_schedule_type): - _schedule = Schedule() - _schedule.time_step = cte.HOUR - _schedule.time_range = cte.DAY - row_cells = _extracted_data.iloc[schedules_per_schedule_type * schedule_types + schedule_day] - if schedule_day == day_types['week_day']: - name = row_cells[0] - data_type = row_cells[1] - _schedule.day_types = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY] - elif schedule_day == day_types['saturday']: - _schedule.day_types = [cte.SATURDAY] - else: - _schedule.day_types = [cte.SUNDAY, cte.HOLIDAY] - _schedule.type = name - _schedule.data_type = SchedulesHelper.data_type_from_comnet(data_type) - if _schedule.data_type == cte.ANY_NUMBER: - values = [] - for cell in row_cells[schedules_per_schedule_type:].to_numpy(): - values.append((float(cell) - 32.) * 5 / 9) - _schedule.values = values - else: - _schedule.values = row_cells[schedules_per_schedule_type:].to_numpy() - schedules.append(_schedule) - - schedules_types = dict({'Occupancy': 0, 'Lights': 3, 'Receptacle': 6, 'Infiltration': 9, 'HVAC Avail': 12, - 'ClgSetPt': 15, 'HtgSetPt': 18}) - - _schedules = [] - for pointer in range(0, 3): - _schedules.append(schedules[schedules_types['Occupancy']+pointer]) - _occupancy.occupancy_schedules = _schedules - _schedules = [] - for pointer in range(0, 3): - _schedules.append(schedules[schedules_types['Lights']+pointer]) - _lighting.schedules = _schedules - _schedules = [] - for pointer in range(0, 3): - _schedules.append(schedules[schedules_types['Receptacle']+pointer]) - _appliances.schedules = _schedules - - _usage.occupancy = _occupancy - _usage.lighting = _lighting - _usage.appliances = _appliances - - _control = ThermalControl() - _schedules = [] - for pointer in range(0, 3): - _schedules.append(schedules[schedules_types['HtgSetPt']+pointer]) - _control.heating_set_point_schedules = _schedules - _schedules = [] - for pointer in range(0, 3): - _schedules.append(schedules[schedules_types['ClgSetPt']+pointer]) - _control.cooling_set_point_schedules = _schedules - _schedules = [] - for pointer in range(0, 3): - _schedules.append(schedules[schedules_types['HVAC Avail']+pointer]) - _control.hvac_availability_schedules = _schedules - _usage.thermal_control = _control - - return _usage - - def _search_archetypes(self, libs_usage): - for item in self._data['lighting']: - comnet_usage = UsageHelper.comnet_from_libs_usage(libs_usage) - if comnet_usage == item: - usage_archetype = self._parse_usage_type(comnet_usage, self._data, self._xls) - return usage_archetype - return None + self._path = base_path def enrich_buildings(self): """ @@ -193,14 +34,14 @@ class ComnetUsageParameters: :return: """ city = self._city + comnet_catalog = UsageCatalogFactory('comnet').catalog for building in city.buildings: - usage = GeometryHelper.libs_usage_from_libs_function(building.function) + usage_name = UsageHelper.comnet_from_hub_usage(building.function) try: - archetype_usage = self._search_archetypes(usage) + archetype_usage = self._search_archetypes(comnet_catalog, usage_name) except KeyError: - sys.stderr.write(f'Building {building.name} has unknown archetype for building function:' - f' {building.function}, that assigns building usage as ' - f'{GeometryHelper.libs_usage_from_libs_function(building.function)}\n') + sys.stderr.write(f'Building {building.name} has unknown usage archetype for building function:' + f' {building.function}') return for internal_zone in building.internal_zones: @@ -210,46 +51,46 @@ class ComnetUsageParameters: raise Exception('Internal zone volume not defined, ACH cannot be calculated') if internal_zone.area <= 0: raise Exception('Internal zone area is zero, ACH cannot be calculated') - if internal_zone.volume <= 0: - raise Exception('Internal zone volume is zero, ACH cannot be calculated') volume_per_area = internal_zone.volume / internal_zone.area usage_zone = Usage() - usage_zone.name = usage - self._assign_values_usage_zone(usage_zone, archetype_usage, volume_per_area) + usage_zone.name = usage_name + self._assign_values(usage_zone, archetype_usage, volume_per_area) usage_zone.percentage = 1 self._calculate_reduced_values_from_extended_library(usage_zone, archetype_usage) internal_zone.usages = [usage_zone] @staticmethod - def _assign_values_usage_zone(usage_zone, archetype, volume_per_area): + def _search_archetypes(comnet_catalog, usage_name): + comnet_archetypes = comnet_catalog.entries('archetypes').usages + for building_archetype in comnet_archetypes: + if str(usage_name) == str(building_archetype.name): + return building_archetype + raise KeyError('archetype not found') + + @staticmethod + def _assign_values(usage_zone, archetype, volume_per_area): # Due to the fact that python is not a typed language, the wrong object type is assigned to # usage_zone.occupancy when writing usage_zone.occupancy = archetype.occupancy. # Same happens for lighting and appliances. Therefore, this walk around has been done. - usage_zone.mechanical_air_change = archetype.mechanical_air_change * cte.METERS_TO_FEET ** 2 \ - * cte.HOUR_TO_MINUTES / cte.METERS_TO_FEET ** 3 / volume_per_area + usage_zone.mechanical_air_change = archetype.ventilation_rate / volume_per_area \ + * cte.HOUR_TO_MINUTES * cte.MINUTES_TO_SECONDS _occupancy = Occupancy() - _occupancy.occupancy_density = archetype.occupancy.occupancy_density * cte.METERS_TO_FEET**2 - _occupancy.sensible_radiative_internal_gain = archetype.occupancy.sensible_radiative_internal_gain \ - * archetype.occupancy.occupancy_density \ - * cte.METERS_TO_FEET**2 * cte.BTU_H_TO_WATTS - _occupancy.latent_internal_gain = archetype.occupancy.latent_internal_gain \ - * archetype.occupancy.occupancy_density \ - * cte.METERS_TO_FEET**2 * cte.BTU_H_TO_WATTS - _occupancy.sensible_convective_internal_gain = archetype.occupancy.sensible_convective_internal_gain \ - * archetype.occupancy.occupancy_density \ - * cte.METERS_TO_FEET**2 * cte.BTU_H_TO_WATTS - _occupancy.occupancy_schedules = archetype.occupancy.occupancy_schedules + _occupancy.occupancy_density = archetype.occupancy.occupancy_density + _occupancy.sensible_radiative_internal_gain = archetype.occupancy.sensible_radiative_internal_gain + _occupancy.latent_internal_gain = archetype.occupancy.latent_internal_gain + _occupancy.sensible_convective_internal_gain = archetype.occupancy.sensible_convective_internal_gain + _occupancy.occupancy_schedules = archetype.occupancy.schedules usage_zone.occupancy = _occupancy _lighting = Lighting() - _lighting.density = archetype.lighting.density / cte.METERS_TO_FEET ** 2 + _lighting.density = archetype.lighting.density _lighting.convective_fraction = archetype.lighting.convective_fraction _lighting.radiative_fraction = archetype.lighting.radiative_fraction _lighting.latent_fraction = archetype.lighting.latent_fraction _lighting.schedules = archetype.lighting.schedules usage_zone.lighting = _lighting _appliances = Appliances() - _appliances.density = archetype.appliances.density / cte.METERS_TO_FEET ** 2 + _appliances.density = archetype.appliances.density _appliances.convective_fraction = archetype.appliances.convective_fraction _appliances.radiative_fraction = archetype.appliances.radiative_fraction _appliances.latent_fraction = archetype.appliances.latent_fraction diff --git a/imports/usage/helpers/usage_helper.py b/imports/usage/helpers/usage_helper.py index 7ddbe01d..b1ae610a 100644 --- a/imports/usage/helpers/usage_helper.py +++ b/imports/usage/helpers/usage_helper.py @@ -106,7 +106,7 @@ class UsageHelper: 'C-14 Gymnasium': 'C-14 Gymnasium'} @staticmethod - def comnet_from_libs_usage(usage): + def comnet_from_hub_usage(usage): """ Get Comnet usage from the given internal usage key :param usage: str @@ -115,7 +115,7 @@ class UsageHelper: try: return UsageHelper._usage_to_comnet[usage] except KeyError: - sys.stderr.write('Error: keyword not found to translate from libs_usage to comnet usage.\n') + sys.stderr.write('Error: keyword not found to translate from hub_usage to comnet usage.\n') @staticmethod def schedules_key(usage): @@ -129,3 +129,41 @@ class UsageHelper: except KeyError: sys.stderr.write('Error: Comnet keyword not found. An update of the Comnet files might have been ' 'done changing the keywords.\n') + + _usage_to_nrcan = { + cte.RESIDENTIAL: 'Multi-unit residential', + cte.SINGLE_FAMILY_HOUSE: 'Multi-unit residential', + cte.MULTI_FAMILY_HOUSE: 'Multi-unit residential', + cte.EDUCATION: 'School/university', + cte.SCHOOL_WITHOUT_SHOWER: 'School/university', + cte.SCHOOL_WITH_SHOWER: 'School/university', + cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'Retail', + cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'Retail', + cte.HOTEL: 'Hotel', + cte.HOTEL_MEDIUM_CLASS: 'Hotel', + cte.DORMITORY: 'Dormitory', + cte.INDUSTRY: 'Manufacturing Facility', + cte.RESTAURANT: 'Dining - family', + cte.HEALTH_CARE: 'Hospital', + cte.RETIREMENT_HOME_OR_ORPHANAGE: 'Multi-unit residential', + cte.OFFICE_AND_ADMINISTRATION: 'Office', + cte.EVENT_LOCATION: 'Convention centre', + cte.HALL: 'Convention centre', + cte.SPORTS_LOCATION: 'Gymnasium', + cte.LABOR: 'Gymnasium', + cte.GREEN_HOUSE: cte.GREEN_HOUSE, + cte.NON_HEATED: cte.NON_HEATED + } + + @staticmethod + def nrcan_from_hub_usage(usage): + """ + Get Nrcan usage from the given internal usage key + :param usage: str + :return: str + """ + try: + return UsageHelper._usage_to_nrcan[usage] + except KeyError: + sys.stderr.write('Error: keyword not found to translate from hub_usage to nrcan usage.\n') + diff --git a/imports/usage/hft_usage_interface.py b/imports/usage/hft_usage_interface.py deleted file mode 100644 index e44832d4..00000000 --- a/imports/usage/hft_usage_interface.py +++ /dev/null @@ -1,280 +0,0 @@ -""" -Hft-based interface, it reads format defined within the CERC team (based on that one used in SimStadt and developed by -the IAF team at hft-Stuttgart) -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Concordia CERC group -Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca -""" -import xmltodict -import copy -from city_model_structure.building_demand.usage import Usage -from city_model_structure.building_demand.internal_gain import InternalGain -from city_model_structure.building_demand.occupancy import Occupancy -from city_model_structure.building_demand.appliances import Appliances -from city_model_structure.building_demand.thermal_control import ThermalControl -from city_model_structure.attributes.schedule import Schedule -import helpers.constants as cte -from imports.usage.helpers.usage_helper import UsageHelper - - -class HftUsageInterface: - """ - HftUsageInterface abstract class - """ - - def __init__(self, base_path, usage_file='ca_library_reduced.xml'): - path = str(base_path / usage_file) - self._usage_archetypes = [] - with open(path) as xml: - self._archetypes = xmltodict.parse(xml.read(), force_list=('zoneUsageVariant', 'zoneUsageType')) - for zone_usage_type in self._archetypes['buildingUsageLibrary']['zoneUsageType']: - usage = zone_usage_type['id'] - usage_archetype = self._parse_zone_usage_type(usage, zone_usage_type) - self._usage_archetypes.append(usage_archetype) - if 'zoneUsageVariant' in zone_usage_type: - for usage_zone_variant in zone_usage_type['zoneUsageVariant']: - usage = usage_zone_variant['id'] - usage_archetype_variant = self._parse_zone_usage_variant(usage, usage_archetype, usage_zone_variant) - self._usage_archetypes.append(usage_archetype_variant) - - @staticmethod - def _parse_zone_usage_type(usage, zone_usage_type): - usage_zone_archetype = Usage() - usage_zone_archetype.name = usage - - if 'occupancy' in zone_usage_type: - _occupancy = Occupancy() - _occupancy.occupancy_density = zone_usage_type['occupancy']['occupancyDensity'] #todo: check units - - if 'internGains' in zone_usage_type['occupancy']: - _internal_gain = InternalGain() - _internal_gain.latent_fraction = zone_usage_type['occupancy']['internGains']['latentFraction'] - _internal_gain.convective_fraction = zone_usage_type['occupancy']['internGains']['convectiveFraction'] - _internal_gain.average_internal_gain = zone_usage_type['occupancy']['internGains']['averageInternGainPerSqm'] - _internal_gain.radiative_fraction = zone_usage_type['occupancy']['internGains']['radiantFraction'] - if 'load' in zone_usage_type['occupancy']['internGains']: - _schedule = Schedule() - _schedule.type = 'internal gains load' - _schedule.time_range = cte.DAY - _schedule.time_step = cte.HOUR - _schedule.data_type = cte.ANY_NUMBER - _schedule.day_types = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY, cte.SATURDAY, - cte.SUNDAY] - _values = zone_usage_type['occupancy']['internGains']['load']['weekDayProfile']['values'] - while ' ' in _values: - _values = _values.replace(' ', ' ') - _values = _values.split() - _values_float = [] - for _value in _values: - _values_float.append(float(_value)) - _schedule.values = _values_float - _internal_gain.schedules = [_schedule] - - usage_zone_archetype.internal_gains = [_internal_gain] - - usage_zone_archetype.hours_day = zone_usage_type['occupancy']['usageHoursPerDay'] - usage_zone_archetype.days_year = zone_usage_type['occupancy']['usageDaysPerYear'] - usage_zone_archetype.occupancy = _occupancy - - if 'endUses' in zone_usage_type: - _thermal_control = ThermalControl() - if 'space_heating' in zone_usage_type['endUses']: - _thermal_control.mean_heating_set_point = \ - zone_usage_type['endUses']['space_heating']['heatingSetPointTemperature'] - _thermal_control.heating_set_back = zone_usage_type['endUses']['space_heating']['heatingSetBackTemperature'] - if 'schedule' in zone_usage_type['endUses']['space_heating']: - _schedule = Schedule() - _schedule.type = 'heating temperature' - _schedule.time_range = cte.DAY - _schedule.time_step = cte.HOUR - _schedule.data_type = cte.ANY_NUMBER - _schedule.day_types = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY, cte.SATURDAY, - cte.SUNDAY] - _values = zone_usage_type['endUses']['space_heating']['schedule']['weekDayProfile']['values'] - while ' ' in _values: - _values = _values.replace(' ', ' ') - _values = _values.split() - _values_float = [] - for _value in _values: - _values_float.append(float(_value)) - _schedule.values = _values_float - _thermal_control.heating_set_point_schedules = [_schedule] - - if 'space_cooling' in zone_usage_type['endUses']: - _thermal_control.mean_cooling_set_point = \ - zone_usage_type['endUses']['space_cooling']['coolingSetPointTemperature'] - if 'schedule' in zone_usage_type['endUses']['space_cooling']: - _schedule = Schedule() - _schedule.type = 'cooling temperature' - _schedule.time_range = cte.DAY - _schedule.time_step = cte.HOUR - _schedule.data_type = cte.ANY_NUMBER - _schedule.day_types = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY, cte.SATURDAY, - cte.SUNDAY] - _values = zone_usage_type['endUses']['space_cooling']['schedule']['weekDayProfile']['values'] - while ' ' in _values: - _values = _values.replace(' ', ' ') - _values = _values.split() - _values_float = [] - for _value in _values: - _values_float.append(float(_value)) - _schedule.values = _values_float - _thermal_control.cooling_set_point_schedules = [_schedule] - - usage_zone_archetype.thermal_control = _thermal_control - - if 'ventilation' in zone_usage_type['endUses'] and zone_usage_type['endUses']['ventilation'] is not None: - usage_zone_archetype.mechanical_air_change = \ - zone_usage_type['endUses']['ventilation']['mechanicalAirChangeRate'] - - # todo: not used or assigned anywhere - if 'domestic_hot_water' in zone_usage_type['endUses']: - # liters to cubic meters - dhw_average_volume_pers_day = float( - zone_usage_type['endUses']['domestic_hot_water']['averageVolumePerPersAndDay']) / 1000 - dhw_preparation_temperature = zone_usage_type['endUses']['domestic_hot_water']['preparationTemperature'] - - if 'all_electrical_appliances' in zone_usage_type['endUses']: - if 'averageConsumptionPerSqmAndYear' in zone_usage_type['endUses']['all_electrical_appliances']: - # kWh to J - usage_zone_archetype.electrical_app_average_consumption_sqm_year = \ - float(zone_usage_type['endUses']['all_electrical_appliances']['averageConsumptionPerSqmAndYear']) \ - * cte.KILO_WATTS_HOUR_TO_JULES - - if 'appliance' in zone_usage_type: - _appliances = Appliances() - _appliances.density = zone_usage_type['appliance']['#text'] #todo: check units - - usage_zone_archetype.appliances = _appliances - - return usage_zone_archetype - - @staticmethod - def _parse_zone_usage_variant(usage, usage_zone, usage_zone_variant): - # the variants mimic the inheritance concept from OOP - usage_zone_archetype = copy.deepcopy(usage_zone) - usage_zone_archetype.name = usage - - if 'occupancy' in usage_zone_variant: - _occupancy = Occupancy() - if 'occupancyDensity' in usage_zone_variant['occupancy']: - _occupancy.occupancy_density = usage_zone_variant['occupancy']['occupancyDensity'] # todo: check units - if 'usageHoursPerDay' in usage_zone_variant['occupancy']: - usage_zone_archetype.hours_day = usage_zone_variant['occupancy']['usageHoursPerDay'] - if 'usageDaysPerYear' in usage_zone_variant['occupancy']: - usage_zone_archetype.days_year = usage_zone_variant['occupancy']['usageDaysPerYear'] - usage_zone_archetype.occupancy = _occupancy - - if 'internGains' in usage_zone_variant['occupancy']: - _internal_gain = InternalGain() - if 'latentFraction' in usage_zone_variant['occupancy']['internGains']: - _internal_gain.latent_fraction = usage_zone_variant['occupancy']['internGains']['latentFraction'] - if 'convectiveFraction' in usage_zone_variant['occupancy']['internGains']: - _internal_gain.convective_fraction = usage_zone_variant['occupancy']['internGains']['convectiveFraction'] - if 'averageInternGainPerSqm' in usage_zone_variant['occupancy']['internGains']: - _internal_gain.average_internal_gain = \ - usage_zone_variant['occupancy']['internGains']['averageInternGainPerSqm'] - if 'radiantFraction' in usage_zone_variant['occupancy']['internGains']: - _internal_gain.radiative_fraction = usage_zone_variant['occupancy']['internGains']['radiantFraction'] - if 'load' in usage_zone_variant['occupancy']['internGains']: - _schedule = Schedule() - _schedule.type = 'internal gains load' - _schedule.time_range = cte.DAY - _schedule.time_step = cte.HOUR - _schedule.data_type = cte.ANY_NUMBER - _schedule.day_types = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY, cte.SATURDAY, - cte.SUNDAY] - _values = usage_zone_variant['occupancy']['internGains']['load']['weekDayProfile']['values'] - while ' ' in _values: - _values = _values.replace(' ', ' ') - _values = _values.split() - _values_float = [] - for _value in _values: - _values_float.append(float(_value)) - _schedule.values = _values_float - _internal_gain.schedules = [_schedule] - - usage_zone_archetype.internal_gains = [_internal_gain] - - if 'endUses' in usage_zone_variant: - _thermal_control = ThermalControl() - if 'space_heating' in usage_zone_variant['endUses']: - if 'heatingSetPointTemperature' in usage_zone_variant['endUses']['space_heating']: - _thermal_control.mean_heating_set_point = \ - usage_zone_variant['endUses']['space_heating']['heatingSetPointTemperature'] - if 'heatingSetBackTemperature' in usage_zone_variant['endUses']['space_heating']: - _thermal_control.heating_set_back = usage_zone_variant['endUses']['space_heating']['heatingSetBackTemperature'] - if 'schedule' in usage_zone_variant['endUses']['space_heating']: - _schedule = Schedule() - _schedule.type = 'heating temperature' - _schedule.time_range = cte.DAY - _schedule.time_step = cte.HOUR - _schedule.data_type = cte.ANY_NUMBER - _schedule.day_types = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY, cte.SATURDAY, - cte.SUNDAY] - _values = usage_zone_variant['endUses']['space_heating']['schedule']['weekDayProfile']['values'] - while ' ' in _values: - _values = _values.replace(' ', ' ') - _values = _values.split() - _values_float = [] - for _value in _values: - _values_float.append(float(_value)) - _schedule.values = _values_float - _thermal_control.heating_set_point_schedules = [_schedule] - - if 'space_cooling' in usage_zone_variant['endUses'] and \ - usage_zone_variant['endUses']['space_cooling'] is not None: - if 'coolingSetPointTemperature' in usage_zone_variant['endUses']['space_cooling']: - _thermal_control.mean_cooling_set_point = \ - usage_zone_variant['endUses']['space_cooling']['coolingSetPointTemperature'] - if 'schedule' in usage_zone_variant['endUses']['space_cooling']: - _schedule = Schedule() - _schedule.type = 'cooling temperature' - _schedule.time_range = cte.DAY - _schedule.time_step = cte.HOUR - _schedule.data_type = cte.ANY_NUMBER - _schedule.day_types = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY, cte.SATURDAY, - cte.SUNDAY] - _values = usage_zone_variant['endUses']['space_cooling']['schedule']['weekDayProfile']['values'] - while ' ' in _values: - _values = _values.replace(' ', ' ') - _values = _values.split() - _values_float = [] - for _value in _values: - _values_float.append(float(_value)) - _schedule.values = _values_float - _thermal_control.cooling_set_point_schedules = [_schedule] - - usage_zone_archetype.thermal_control = _thermal_control - - if 'ventilation' in usage_zone_variant['endUses'] and usage_zone_variant['endUses']['ventilation'] is not None: - usage_zone_archetype.mechanical_air_change = \ - usage_zone_variant['endUses']['ventilation']['mechanicalAirChangeRate'] - - if 'appliance' in usage_zone_variant: - _appliances = Appliances() - _appliances.density = usage_zone_variant['appliance']['#text'] # todo: check units - - usage_zone_archetype.appliances = _appliances - - return usage_zone_archetype - - def _search_archetype(self, libs_usage): - building_usage = UsageHelper().hft_from_libs_usage(libs_usage) - for building_archetype in self._usage_archetypes: - if building_archetype.name == building_usage: - return building_archetype - return None - - @staticmethod - def _assign_values(usage, archetype): - usage_zone = Usage() - usage_zone.name = usage - usage_zone.internal_gains = copy.deepcopy(archetype.internal_gains) - usage_zone.mechanical_air_change = archetype.mechanical_air_change - usage_zone.occupancy = copy.deepcopy(archetype.occupancy) - usage_zone.appliances = copy.deepcopy(archetype.appliances) - usage_zone.thermal_control = copy.deepcopy(archetype.thermal_control) - usage_zone.days_year = archetype.days_year - usage_zone.hours_day = archetype.hours_day - return usage_zone diff --git a/imports/usage/hft_usage_parameters.py b/imports/usage/hft_usage_parameters.py deleted file mode 100644 index 3d869242..00000000 --- a/imports/usage/hft_usage_parameters.py +++ /dev/null @@ -1,42 +0,0 @@ -""" -HftUsageParameters model the usage properties -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Concordia CERC group -Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca -""" -import sys - -from imports.geometry.helpers.geometry_helper import GeometryHelper -from imports.usage.hft_usage_interface import HftUsageInterface -from imports.usage.helpers.usage_helper import UsageHelper - - -class HftUsageParameters(HftUsageInterface): - """ - HftUsageParameters class - """ - def __init__(self, city, base_path): - super().__init__(base_path, 'de_library.xml') - self._city = city - - def enrich_buildings(self): - """ - Returns the city with the usage parameters assigned to the buildings - :return: - """ - city = self._city - for building in city.buildings: - usage = GeometryHelper().libs_usage_from_libs_function(building.function) - try: - archetype = self._search_archetype(usage) - except KeyError: - sys.stderr.write(f'Building {building.name} has unknown archetype for building function:' - f' {building.function}, that assigns building usage as ' - f'{GeometryHelper().libs_usage_from_libs_function(building.function)}\n') - return - - for internal_zone in building.internal_zones: - libs_usage = GeometryHelper().libs_usage_from_libs_function(building.function) - usage_zone = self._assign_values(UsageHelper().hft_from_libs_usage(libs_usage), archetype) - usage_zone.percentage = 1 - internal_zone.usages = [usage_zone] diff --git a/imports/usage/nrcan_usage_parameters.py b/imports/usage/nrcan_usage_parameters.py new file mode 100644 index 00000000..ea2b1a4b --- /dev/null +++ b/imports/usage/nrcan_usage_parameters.py @@ -0,0 +1,191 @@ +""" +NrcanUsageParameters extracts the usage properties from NRCAN catalog and assigns to each building +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca +""" +import copy +import sys +import numpy + +import helpers.constants as cte +from imports.usage.helpers.usage_helper import UsageHelper +from city_model_structure.building_demand.usage import Usage +from city_model_structure.building_demand.lighting import Lighting +from city_model_structure.building_demand.occupancy import Occupancy +from city_model_structure.building_demand.appliances import Appliances +from city_model_structure.building_demand.thermal_control import ThermalControl +from city_model_structure.attributes.schedule import Schedule +from city_model_structure.building_demand.internal_gain import InternalGain +from catalog_factories.usage_catalog_factory import UsageCatalogFactory + + +class NrcanUsageParameters: + """ + NrcanUsageParameters class + """ + def __init__(self, city, base_path): + self._city = city + self._path = base_path + + def enrich_buildings(self): + """ + Returns the city with the usage parameters assigned to the buildings + :return: + """ + city = self._city + nrcan_catalog = UsageCatalogFactory('nrcan').catalog + + for building in city.buildings: + usage_name = UsageHelper.nrcan_from_hub_usage(building.function) + try: + archetype_usage = self._search_archetypes(nrcan_catalog, usage_name) + except KeyError: + sys.stderr.write(f'Building {building.name} has unknown usage archetype for building function:' + f' {building.function}') + return + + for internal_zone in building.internal_zones: + if internal_zone.area is None: + raise Exception('Internal zone area not defined, ACH cannot be calculated') + if internal_zone.volume is None: + raise Exception('Internal zone volume not defined, ACH cannot be calculated') + if internal_zone.area <= 0: + raise Exception('Internal zone area is zero, ACH cannot be calculated') + volume_per_area = internal_zone.volume / internal_zone.area + usage_zone = Usage() + usage_zone.name = usage_name + self._assign_values(usage_zone, archetype_usage, volume_per_area) + usage_zone.percentage = 1 + self._calculate_reduced_values_from_extended_library(usage_zone, archetype_usage) + + internal_zone.usages = [usage_zone] + + @staticmethod + def _search_archetypes(comnet_catalog, usage_name): + comnet_archetypes = comnet_catalog.entries('archetypes').usages + for building_archetype in comnet_archetypes: + if str(usage_name) == str(building_archetype.name): + return building_archetype + raise KeyError('archetype not found') + + @staticmethod + def _assign_values(usage_zone, archetype, volume_per_area): + # Due to the fact that python is not a typed language, the wrong object type is assigned to + # usage_zone.occupancy when writing usage_zone.occupancy = archetype.occupancy. + # Same happens for lighting and appliances. Therefore, this walk around has been done. + if archetype.mechanical_air_change > 0: + usage_zone.mechanical_air_change = archetype.mechanical_air_change + elif archetype.ventilation_rate > 0: + usage_zone.mechanical_air_change = archetype.ventilation_rate / volume_per_area \ + * cte.HOUR_TO_MINUTES * cte.MINUTES_TO_SECONDS + else: + usage_zone.mechanical_air_change = 0 + _occupancy = Occupancy() + _occupancy.occupancy_density = archetype.occupancy.occupancy_density + _occupancy.sensible_radiative_internal_gain = archetype.occupancy.sensible_radiative_internal_gain + _occupancy.latent_internal_gain = archetype.occupancy.latent_internal_gain + _occupancy.sensible_convective_internal_gain = archetype.occupancy.sensible_convective_internal_gain + _occupancy.occupancy_schedules = archetype.occupancy.occupancy_schedules + usage_zone.occupancy = _occupancy + _lighting = Lighting() + _lighting.density = archetype.lighting.density + _lighting.convective_fraction = archetype.lighting.convective_fraction + _lighting.radiative_fraction = archetype.lighting.radiative_fraction + _lighting.latent_fraction = archetype.lighting.latent_fraction + _lighting.schedules = archetype.lighting.schedules + usage_zone.lighting = _lighting + _appliances = Appliances() + _appliances.density = archetype.appliances.density + _appliances.convective_fraction = archetype.appliances.convective_fraction + _appliances.radiative_fraction = archetype.appliances.radiative_fraction + _appliances.latent_fraction = archetype.appliances.latent_fraction + _appliances.schedules = archetype.appliances.schedules + usage_zone.appliances = _appliances + _control = ThermalControl() + _control.cooling_set_point_schedules = archetype.thermal_control.cooling_set_point_schedules + _control.heating_set_point_schedules = archetype.thermal_control.heating_set_point_schedules + _control.hvac_availability_schedules = archetype.thermal_control.hvac_availability_schedules + usage_zone.thermal_control = _control + + @staticmethod + def _calculate_reduced_values_from_extended_library(usage_zone, archetype): + number_of_days_per_type = {'WD': 251, 'Sat': 52, 'Sun': 62} + total = 0 + for schedule in archetype.thermal_control.hvac_availability_schedules: + if schedule.day_types[0] == cte.SATURDAY: + for value in schedule.values: + total += value * number_of_days_per_type['Sat'] + elif schedule.day_types[0] == cte.SUNDAY: + for value in schedule.values: + total += value * number_of_days_per_type['Sun'] + else: + for value in schedule.values: + total += value * number_of_days_per_type['WD'] + + usage_zone.hours_day = total / 365 + usage_zone.days_year = 365 + + @staticmethod + def _calculate_internal_gains(archetype): + + _DAYS = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY, cte.SATURDAY, cte.SUNDAY, cte.HOLIDAY] + _number_of_days_per_type = [51, 50, 50, 50, 50, 52, 52, 10] + + _mean_internal_gain = InternalGain() + _mean_internal_gain.type = 'mean_value_of_internal_gains' + _base_schedule = Schedule() + _base_schedule.type = cte.INTERNAL_GAINS + _base_schedule.time_range = cte.DAY + _base_schedule.time_step = cte.HOUR + _base_schedule.data_type = cte.FRACTION + + _latent_heat_gain = archetype.occupancy.latent_internal_gain + _convective_heat_gain = archetype.occupancy.sensible_convective_internal_gain + _radiative_heat_gain = archetype.occupancy.sensible_radiative_internal_gain + _total_heat_gain = (_latent_heat_gain + _convective_heat_gain + _radiative_heat_gain) + + _schedule_values = numpy.zeros([24, 8]) + _sum = 0 + for day, _schedule in enumerate(archetype.occupancy.schedules): + for v, value in enumerate(_schedule.values): + _schedule_values[v, day] = value * _total_heat_gain + _sum += value * _total_heat_gain * _number_of_days_per_type[day] + + _total_heat_gain += archetype.lighting.density + archetype.appliances.density + _latent_heat_gain += archetype.lighting.latent_fraction * archetype.lighting.density\ + + archetype.appliances.latent_fraction * archetype.appliances.density + _radiative_heat_gain = archetype.lighting.radiative_fraction * archetype.lighting.density \ + + archetype.appliances.radiative_fraction * archetype.appliances.density + _convective_heat_gain = archetype.lighting.convective_fraction * archetype.lighting.density \ + + archetype.appliances.convective_fraction * archetype.appliances.density + + for day, _schedule in enumerate(archetype.lighting.schedules): + for v, value in enumerate(_schedule.values): + _schedule_values[v, day] += value * archetype.lighting.density + _sum += value * archetype.lighting.density * _number_of_days_per_type[day] + + for day, _schedule in enumerate(archetype.appliances.schedules): + for v, value in enumerate(_schedule.values): + _schedule_values[v, day] += value * archetype.appliances.density + _sum += value * archetype.appliances.density * _number_of_days_per_type[day] + + _latent_fraction = _latent_heat_gain / _total_heat_gain + _radiative_fraction = _radiative_heat_gain / _total_heat_gain + _convective_fraction = _convective_heat_gain / _total_heat_gain + _average_internal_gain = _sum / _total_heat_gain + + _schedules = [] + for day in range(0, len(_DAYS)): + _schedule = copy.deepcopy(_base_schedule) + _schedule.day_types = [_DAYS[day]] + _schedule.values = _schedule_values[:day] + _schedules.append(_schedule) + + _mean_internal_gain.average_internal_gain = _average_internal_gain + _mean_internal_gain.latent_fraction = _latent_fraction + _mean_internal_gain.convective_fraction = _convective_fraction + _mean_internal_gain.radiative_fraction = _radiative_fraction + _mean_internal_gain.schedules = _schedules + + return [_mean_internal_gain] diff --git a/imports/usage_factory.py b/imports/usage_factory.py index 3ec4e45d..873812ff 100644 --- a/imports/usage_factory.py +++ b/imports/usage_factory.py @@ -7,9 +7,8 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca """ from pathlib import Path -from imports.usage.hft_usage_parameters import HftUsageParameters from imports.usage.comnet_usage_parameters import ComnetUsageParameters - +from imports.usage.nrcan_usage_parameters import NrcanUsageParameters class UsageFactory: """ @@ -22,20 +21,19 @@ class UsageFactory: self._city = city self._base_path = base_path - def _hft(self): - """ - Enrich the city with HFT usage library - """ - self._city.level_of_detail.usage = 2 - HftUsageParameters(self._city, self._base_path).enrich_buildings() - def _comnet(self): """ Enrich the city with COMNET usage library """ - self._city.level_of_detail.usage = 2 + self._city.level_of_detail.usage_name = 2 ComnetUsageParameters(self._city, self._base_path).enrich_buildings() + def _nrcan(self): + """ + Enrich the city with NRCAN usage library + """ + return NrcanUsageParameters(self._city, self._base_path).enrich_buildings() + def enrich(self): """ Enrich the city given to the class using the usage factory given handler diff --git a/unittests/test_construction_factory.py b/unittests/test_construction_factory.py index 6ba75ee9..5be1db00 100644 --- a/unittests/test_construction_factory.py +++ b/unittests/test_construction_factory.py @@ -122,7 +122,7 @@ class TestConstructionFactory(TestCase): self.assertIsNone(thermal_zone.ordinate_number, 'thermal_zone ordinate number is not none') self.assertIsNotNone(thermal_zone.view_factors_matrix, 'thermal_zone view factors matrix is none') self.assertIsNotNone(thermal_zone.total_floor_area, 'thermal zone total_floor_area is none') - self.assertIsNone(thermal_zone.usage, 'thermal_zone usage is not none') + self.assertIsNone(thermal_zone.usage_name, 'thermal_zone usage is not none') self.assertIsNone(thermal_zone.hours_day, 'thermal_zone hours a day is not none') self.assertIsNone(thermal_zone.days_year, 'thermal_zone days a year is not none') self.assertIsNone(thermal_zone.mechanical_air_change, 'thermal_zone mechanical air change is not none') diff --git a/unittests/test_enrichement.py b/unittests/test_enrichement.py index 1e7fc6d3..c63922f2 100644 --- a/unittests/test_enrichement.py +++ b/unittests/test_enrichement.py @@ -55,7 +55,7 @@ class TestGeometryFactory(TestCase): def _check_thermal_zone(self, thermal_zone): self.assertIsNotNone(thermal_zone.id, 'thermal_zone id is none') - self.assertIsNotNone(thermal_zone.usage, 'thermal_zone usage is not none') + self.assertIsNotNone(thermal_zone.usage_name, 'thermal_zone usage is not none') self.assertIsNotNone(thermal_zone.hours_day, 'thermal_zone hours a day is none') self.assertIsNotNone(thermal_zone.days_year, 'thermal_zone days a year is none') self.assertIsNotNone(thermal_zone.occupancy, 'thermal_zone occupancy is none') @@ -91,7 +91,7 @@ class TestGeometryFactory(TestCase): def _test_hft(self, file): _construction_keys = ['nrel'] - _usage_keys = ['comnet', 'hft'] + _usage_keys = ['comnet', 'nrcan'] for construction_key in _construction_keys: for usage_key in _usage_keys: # construction factory called first From 4080b0ad8f6e52f68b53d8bb87daa4bcea49da24 Mon Sep 17 00:00:00 2001 From: Pilar Date: Wed, 7 Dec 2022 11:04:04 -0500 Subject: [PATCH 4/8] bug in function assignment. Dictionaries must be reviewed --- imports/geometry/helpers/geometry_helper.py | 4 +-- imports/usage_factory.py | 1 + unittests/test_usage_factory.py | 34 --------------------- 3 files changed, 3 insertions(+), 36 deletions(-) diff --git a/imports/geometry/helpers/geometry_helper.py b/imports/geometry/helpers/geometry_helper.py index afbd15a0..389ff6ac 100644 --- a/imports/geometry/helpers/geometry_helper.py +++ b/imports/geometry/helpers/geometry_helper.py @@ -197,7 +197,7 @@ class GeometryHelper: 'W1': cte.PRIMARY_SCHOOL, 'W2': cte.PRIMARY_SCHOOL, 'W3': cte.SECONDARY_SCHOOL, - 'W4': cte.SECONDARY_SCHOOL, + 'W4': cte.EDUCATION, 'W5': cte.SECONDARY_SCHOOL, 'W6': cte.SECONDARY_SCHOOL, 'W7': cte.SECONDARY_SCHOOL, @@ -225,7 +225,7 @@ class GeometryHelper: 'strip mall': cte.STRIP_MALL, 'warehouse': cte.WAREHOUSE, 'primary school': cte.PRIMARY_SCHOOL, - 'secondary school': cte.SECONDARY_SCHOOL, + 'secondary school': cte.EDUCATION, 'office': cte.MEDIUM_OFFICE, 'large office': cte.LARGE_OFFICE } diff --git a/imports/usage_factory.py b/imports/usage_factory.py index 873812ff..ed567b89 100644 --- a/imports/usage_factory.py +++ b/imports/usage_factory.py @@ -10,6 +10,7 @@ from pathlib import Path from imports.usage.comnet_usage_parameters import ComnetUsageParameters from imports.usage.nrcan_usage_parameters import NrcanUsageParameters + class UsageFactory: """ UsageFactory class diff --git a/unittests/test_usage_factory.py b/unittests/test_usage_factory.py index 1a593493..39cbe500 100644 --- a/unittests/test_usage_factory.py +++ b/unittests/test_usage_factory.py @@ -125,37 +125,3 @@ class TestUsageFactory(TestCase): self.assertIsNotNone(appliances.schedules, 'appliances schedule is none') self.assertIsNotNone(usage_zone.thermal_control.hvac_availability_schedules, 'control hvac availability is none') - - def test_import_hft(self): - """ - Enrich the city with the usage information from hft and verify it - """ - file = 'pluto_building.gml' - city = self._get_citygml(file) - for building in city.buildings: - building.function = GeometryHelper.libs_function_from_pluto(building.function) - - UsageFactory('hft', city).enrich() - self._check_buildings(city) - for building in city.buildings: - for internal_zone in building.internal_zones: - self.assertIsNot(len(internal_zone.usages), 0, 'no building usage_zones defined') - for usage_zone in internal_zone.usages: - self._check_usage_zone(usage_zone) - self.assertIsNone(usage_zone.mechanical_air_change, 'mechanical air change is not none') - self.assertIsNotNone(usage_zone.thermal_control.heating_set_point_schedules, - 'control heating set point schedule is none') - self.assertIsNotNone(usage_zone.thermal_control.cooling_set_point_schedules, - 'control cooling set point schedule is none') - self.assertIsNotNone(usage_zone.occupancy, 'occupancy is none') - occupancy = usage_zone.occupancy - self.assertIsNotNone(occupancy.occupancy_density, 'occupancy density is none') - self.assertIsNone(occupancy.latent_internal_gain, 'occupancy latent internal gain is none') - self.assertIsNone(occupancy.sensible_convective_internal_gain, - 'occupancy sensible convective internal gain is not none') - self.assertIsNone(occupancy.sensible_radiative_internal_gain, - 'occupancy sensible radiant internal gain is not none') - self.assertIsNone(occupancy.occupancy_schedules, 'occupancy schedule is not none') - self.assertIsNone(occupancy.occupants, 'occupancy density is not none') - self.assertIsNone(usage_zone.lighting, 'lighting is not none') - self.assertIsNone(usage_zone.appliances, 'appliances is not none') From c0e60f27c75edf097fca8ed7aa5ebcff7285af2a Mon Sep 17 00:00:00 2001 From: Pilar Date: Thu, 15 Dec 2022 07:42:59 -0500 Subject: [PATCH 5/8] completed NRCAN usage catalog importer and NRCAN usage importer started NRCAN construction catalog importer and NRCAN construction importer but not working! --- .../construction/construction_helper.py | 59 ++++++ .../construction/construction_helpers.py | 43 ---- .../construction/nrcan_catalog.py | 127 ++++++++++++ .../construction/nrel_catalog.py | 11 +- .../construction_catalog_factory.py | 8 + catalog_factories/usage/comnet_catalog.py | 42 +--- catalog_factories/usage/nrcan_catalog.py | 92 +++++---- catalog_factories/usage/usage_helper.py | 1 + city_model_structure/building_demand/usage.py | 1 - data/construction/nrcan.xml | 76 +++++++ data/usage/nrcan.xml | 8 +- .../helpers/construction_helper.py | 1 + .../construction/nrcan_physics_parameters.py | 188 ++++++++++++++++++ .../construction/nrel_physics_parameters.py | 3 +- imports/construction_factory.py | 12 +- imports/usage/comnet_usage_parameters.py | 25 +++ imports/usage/helpers/usage_helper.py | 8 +- imports/usage/nrcan_usage_parameters.py | 114 ++++------- unittests/test_enrichement.py | 5 +- 19 files changed, 617 insertions(+), 207 deletions(-) create mode 100644 catalog_factories/construction/construction_helper.py delete mode 100644 catalog_factories/construction/construction_helpers.py create mode 100644 catalog_factories/construction/nrcan_catalog.py create mode 100644 data/construction/nrcan.xml create mode 100644 imports/construction/nrcan_physics_parameters.py diff --git a/catalog_factories/construction/construction_helper.py b/catalog_factories/construction/construction_helper.py new file mode 100644 index 00000000..3708fbd0 --- /dev/null +++ b/catalog_factories/construction/construction_helper.py @@ -0,0 +1,59 @@ +from helpers import constants as cte + + +class ConstructionHelper: + """ + Construction helper class + """ + nrel_to_function = { + 'residential': cte.RESIDENTIAL, + 'midrise apartment': cte.MID_RISE_APARTMENT, + 'high-rise apartment': cte.HIGH_RISE_APARTMENT, + 'small office': cte.SMALL_OFFICE, + 'medium office': cte.MEDIUM_OFFICE, + 'large office': cte.LARGE_OFFICE, + 'primary school': cte.PRIMARY_SCHOOL, + 'secondary school': cte.SECONDARY_SCHOOL, + 'stand-alone retail': cte.STAND_ALONE_RETAIL, + 'hospital': cte.HOSPITAL, + 'outpatient healthcare': cte.OUT_PATIENT_HEALTH_CARE, + 'strip mall': cte.STRIP_MALL, + 'supermarket': cte.SUPERMARKET, + 'warehouse': cte.WAREHOUSE, + 'quick service restaurant': cte.QUICK_SERVICE_RESTAURANT, + 'full service restaurant': cte.FULL_SERVICE_RESTAURANT, + 'small hotel': cte.SMALL_HOTEL, + 'large hotel': cte.LARGE_HOTEL, + 'industry': cte.INDUSTRY + } + + nrcan_to_function = { + 'residential': cte.RESIDENTIAL, + } + + reference_standard_to_construction_period = { + 'non_standard_dompark': '1900 - 2004', + 'ASHRAE 90.1_2004': '2004 - 2009', + 'ASHRAE 189.1_2009': '2009 - PRESENT' + } + + nrel_surfaces_types_to_hub_types = { + 'exterior wall': cte.WALL, + 'interior wall': cte.INTERIOR_WALL, + 'ground wall': cte.GROUND_WALL, + 'exterior slab': cte.GROUND, + 'attic floor': cte.ATTIC_FLOOR, + 'interior slab': cte.INTERIOR_SLAB, + 'roof': cte.ROOF + } + nrcan_surfaces_types_to_hub_types = { + 'Wall_Outdoors': cte.WALL, + 'RoofCeiling_Outdoors': cte.ROOF, + 'Floor_Outdoors': cte.ATTIC_FLOOR, + 'Window_Outdoors': cte.WINDOW, + 'Skylight_Outdoors': cte.SKYLIGHT, + 'Door_Outdoors': cte.DOOR, + 'Wall_Ground': cte.GROUND_WALL, + 'RoofCeiling_Ground': cte.GROUND_WALL, + 'Floor_Ground': cte.GROUND + } diff --git a/catalog_factories/construction/construction_helpers.py b/catalog_factories/construction/construction_helpers.py deleted file mode 100644 index b19cfc3d..00000000 --- a/catalog_factories/construction/construction_helpers.py +++ /dev/null @@ -1,43 +0,0 @@ -from helpers import constants as cte - -nrel_to_function = { - 'residential': cte.RESIDENTIAL, - 'midrise apartment': cte.MID_RISE_APARTMENT, - 'high-rise apartment': cte.HIGH_RISE_APARTMENT, - 'small office': cte.SMALL_OFFICE, - 'medium office': cte.MEDIUM_OFFICE, - 'large office': cte.LARGE_OFFICE, - 'primary school': cte.PRIMARY_SCHOOL, - 'secondary school': cte.SECONDARY_SCHOOL, - 'stand-alone retail': cte.STAND_ALONE_RETAIL, - 'hospital': cte.HOSPITAL, - 'outpatient healthcare': cte.OUT_PATIENT_HEALTH_CARE, - 'strip mall': cte.STRIP_MALL, - 'supermarket': cte.SUPERMARKET, - 'warehouse': cte.WAREHOUSE, - 'quick service restaurant': cte.QUICK_SERVICE_RESTAURANT, - 'full service restaurant': cte.FULL_SERVICE_RESTAURANT, - 'small hotel': cte.SMALL_HOTEL, - 'large hotel': cte.LARGE_HOTEL, - 'industry': cte.INDUSTRY -} - -nrcan_to_function = { - 'residential': cte.RESIDENTIAL, -} - -reference_standard_to_construction_period = { - 'non_standard_dompark': '1900 - 2004', - 'ASHRAE 90.1_2004': '2004 - 2009', - 'ASHRAE 189.1_2009': '2009 - PRESENT' -} - -nrel_surfaces_types_to_hub_types = { - 'exterior wall': cte.WALL, - 'interior wall': cte.INTERIOR_WALL, - 'ground wall': cte.GROUND_WALL, - 'exterior slab': cte.GROUND, - 'attic floor': cte.ATTIC_FLOOR, - 'interior slab': cte.INTERIOR_SLAB, - 'roof': cte.ROOF -} \ No newline at end of file diff --git a/catalog_factories/construction/nrcan_catalog.py b/catalog_factories/construction/nrcan_catalog.py new file mode 100644 index 00000000..dafa0bdb --- /dev/null +++ b/catalog_factories/construction/nrcan_catalog.py @@ -0,0 +1,127 @@ +""" +NRCAN construction catalog +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca +""" + +import json +import urllib.request +import xmltodict +import string + +import helpers.constants as cte +from catalog_factories.catalog import Catalog +from catalog_factories.data_models.usages.content import Content +from catalog_factories.construction.construction_helper import ConstructionHelper +from catalog_factories.data_models.construction.construction import Construction +from catalog_factories.data_models.construction.archetype import Archetype + + +class NrcanCatalog(Catalog): + def __init__(self, path): + path = str(path / 'nrcan.xml') + self._content = None + self._g_value_per_hdd = [] + self._thermal_transmittance_per_hdd_and_surface = {} + self._window_ratios = {} + with open(path) as xml: + self._metadata = xmltodict.parse(xml.read()) + self._base_url_archetypes = self._metadata['nrcan']['@base_url_archetypes'] + self._base_url_construction = self._metadata['nrcan']['@base_url_construction'] + self._load_window_ratios() + self._load_construction_values() + self._content = Content(self._load_archetypes()) + + def _load_window_ratios(self): + for standard in self._metadata['nrcan']['standards_per_function']['standard']: + url = f'{self._base_url_archetypes}{standard["file_location"]}' + # todo: read from file + self._window_ratios = {'Mean': 0.2, 'North': 0.2, 'East': 0.2, 'South': 0.2, 'West': 0.2} + + def _load_construction_values(self): + for standard in self._metadata['nrcan']['standards_per_period']['standard']: + g_value_url = f'{self._base_url_construction}{standard["g_value_location"]}' + punc = '() Catalog: """ diff --git a/catalog_factories/usage/comnet_catalog.py b/catalog_factories/usage/comnet_catalog.py index a68ea03c..6edf316d 100644 --- a/catalog_factories/usage/comnet_catalog.py +++ b/catalog_factories/usage/comnet_catalog.py @@ -28,6 +28,7 @@ class ComnetCatalog(Catalog): self._archetypes = self._read_archetype_file() self._schedules = self._read_schedules_file() + # todo: comment with @Guille, this hypotheses should go in the import factory? sensible_convective = ch().comnet_occupancy_sensible_convective sensible_radiative = ch().comnet_occupancy_sensible_radiant lighting_convective = ch().comnet_lighting_convective @@ -41,7 +42,8 @@ class ComnetCatalog(Catalog): for schedule_key in self._archetypes['schedules_key']: comnet_usage = schedule_key schedule_name = self._archetypes['schedules_key'][schedule_key] - hours_day = self._calculate_hours_day(schedule_name) + hours_day = None + days_year = None occupancy_archetype = self._archetypes['occupancy'][comnet_usage] lighting_archetype = self._archetypes['lighting'][comnet_usage] appliances_archetype = self._archetypes['plug loads'][comnet_usage] @@ -86,29 +88,9 @@ class ComnetCatalog(Catalog): self._schedules[schedule_name]['Receptacle']) # get thermal control - max_heating_setpoint = cte.MIN_FLOAT - min_heating_setpoint = cte.MAX_FLOAT - - for schedule in self._schedules[schedule_name]['HtgSetPt']: - if schedule.values is None: - max_heating_setpoint = None - min_heating_setpoint = None - break - if max(schedule.values) > max_heating_setpoint: - max_heating_setpoint = max(schedule.values) - if min(schedule.values) < min_heating_setpoint: - min_heating_setpoint = min(schedule.values) - - min_cooling_setpoint = cte.MAX_FLOAT - for schedule in self._schedules[schedule_name]['ClgSetPt']: - if schedule.values is None: - min_cooling_setpoint = None - break - if min(schedule.values) < min_cooling_setpoint: - min_cooling_setpoint = min(schedule.values) - thermal_control = ThermalControl(max_heating_setpoint, - min_heating_setpoint, - min_cooling_setpoint, + thermal_control = ThermalControl(None, + None, + None, self._schedules[schedule_name]['HVAC Avail'], self._schedules[schedule_name]['HtgSetPt'], self._schedules[schedule_name]['ClgSetPt'] @@ -116,7 +98,7 @@ class ComnetCatalog(Catalog): usages.append(Usage(comnet_usage, hours_day, - 365, + days_year, mechanical_air_change, ventilation_rate, occupancy, @@ -202,16 +184,6 @@ class ComnetCatalog(Catalog): 'schedules_key': schedules_key } - def _calculate_hours_day(self, function): - days = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY, cte.SATURDAY, cte.SUNDAY, cte.HOLIDAY] - number_of_days_per_type = [51, 50, 50, 50, 50, 52, 52, 10] - total = 0 - for schedule in self._schedules[function]['HVAC Avail']: - yearly_days = number_of_days_per_type[days.index(schedule.day_types[0])] - for value in schedule.values: - total += value * yearly_days - return total / 365 - def names(self, category=None): """ Get the catalog elements names diff --git a/catalog_factories/usage/nrcan_catalog.py b/catalog_factories/usage/nrcan_catalog.py index 5842bc3f..0e1e8882 100644 --- a/catalog_factories/usage/nrcan_catalog.py +++ b/catalog_factories/usage/nrcan_catalog.py @@ -3,6 +3,7 @@ NRCAN usage catalog 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 """ import json @@ -50,59 +51,84 @@ class NrcanCatalog(Catalog): return Schedule(hub_type, raw['values'], data_type, time_step, time_range, day_types) def _load_schedules(self): - usage = self._metadata['nrcan']['standards']['usage'] + usage = self._metadata['nrcan'] url = f'{self._base_url}{usage["schedules_location"]}' + _schedule_types = [] with urllib.request.urlopen(url) as json_file: schedules_type = json.load(json_file) for schedule_type in schedules_type['tables']['schedules']['table']: schedule = NrcanCatalog._extract_schedule(schedule_type) - if schedule is not None: - self._schedules[schedule_type['name']] = schedule + if schedule_type['name'] not in _schedule_types: + _schedule_types.append(schedule_type['name']) + if schedule is not None: + self._schedules[schedule_type['name']] = [schedule] + else: + if schedule is not None: + _schedules = self._schedules[schedule_type['name']] + _schedules.append(schedule) + self._schedules[schedule_type['name']] = _schedules - def _get_schedule(self, name): + def _get_schedules(self, name): if name in self._schedules: return self._schedules[name] def _load_archetypes(self): usages = [] - name = self._metadata['nrcan']['standards']['usage'] + name = self._metadata['nrcan'] url = f'{self._base_url}{name["space_types_location"]}' with urllib.request.urlopen(url) as json_file: space_types = json.load(json_file)['tables']['space_types']['table'] - space_types = [st for st in space_types if st['building_type'] == 'Space Function'] +# space_types = [st for st in space_types if st['building_type'] == 'Space Function'] + space_types = [st for st in space_types if st['space_type'] == 'WholeBuilding'] for space_type in space_types: - usage_type = space_type['space_type'] - mechanical_air_change = space_type['ventilation_air_changes'] - ventilation_rate = space_type['ventilation_per_area'] - if ventilation_rate == 0: - ventilation_rate = space_type['ventilation_per_person'] +# usage_type = space_type['space_type'] + usage_type = space_type['building_type'] occupancy_schedule_name = space_type['occupancy_schedule'] lighting_schedule_name = space_type['lighting_schedule'] appliance_schedule_name = space_type['electric_equipment_schedule'] - # thermal control + hvac_schedule_name = space_type['exhaust_schedule'] + if 'FAN' in hvac_schedule_name: + hvac_schedule_name = hvac_schedule_name.replace('FAN', 'Fan') heating_setpoint_schedule_name = space_type['heating_setpoint_schedule'] cooling_setpoint_schedule_name = space_type['cooling_setpoint_schedule'] - occupancy_schedule = self._get_schedule(occupancy_schedule_name) - lighting_schedule = self._get_schedule(lighting_schedule_name) - appliance_schedule = self._get_schedule(appliance_schedule_name) - heating_schedule = self._get_schedule(heating_setpoint_schedule_name) - cooling_schedule = self._get_schedule(cooling_setpoint_schedule_name) + occupancy_schedule = self._get_schedules(occupancy_schedule_name) + lighting_schedule = self._get_schedules(lighting_schedule_name) + appliance_schedule = self._get_schedules(appliance_schedule_name) + heating_schedule = self._get_schedules(heating_setpoint_schedule_name) + cooling_schedule = self._get_schedules(cooling_setpoint_schedule_name) + hvac_availability = self._get_schedules(hvac_schedule_name) occupancy_density = space_type['occupancy_per_area'] - lighting_density = space_type['lighting_per_area'] + + # ACH + mechanical_air_change = space_type['ventilation_air_changes'] + # cfm/ft2 to m3/m2.s + ventilation_rate = space_type['ventilation_per_area'] / (cte.METERS_TO_FEET * cte.MINUTES_TO_SECONDS) + if ventilation_rate == 0: + # cfm/person to m3/m2.s + ventilation_rate = space_type['ventilation_per_person'] / occupancy_density\ + / (cte.METERS_TO_FEET * cte.MINUTES_TO_SECONDS) + + # W/sqft to W/m2 + lighting_density = space_type['lighting_per_area'] * cte.METERS_TO_FEET * cte.METERS_TO_FEET lighting_radiative_fraction = space_type['lighting_fraction_radiant'] lighting_convective_fraction = 0 if lighting_radiative_fraction is not None: lighting_convective_fraction = 1 - lighting_radiative_fraction lighting_latent_fraction = 0 - appliances_density = space_type['electric_equipment_per_area'] + # W/sqft to W/m2 + appliances_density = space_type['electric_equipment_per_area'] * cte.METERS_TO_FEET * cte.METERS_TO_FEET appliances_radiative_fraction = space_type['electric_equipment_fraction_radiant'] - appliances_convective_fraction = 0 - if appliances_radiative_fraction is not None: - appliances_convective_fraction = 1 - appliances_radiative_fraction appliances_latent_fraction = space_type['electric_equipment_fraction_latent'] + appliances_convective_fraction = 0 + if appliances_radiative_fraction is not None and appliances_latent_fraction is not None: + appliances_convective_fraction = 1 - appliances_radiative_fraction - appliances_latent_fraction - occupancy = Occupancy(occupancy_density, 0, 0, 0, occupancy_schedule) + occupancy = Occupancy(occupancy_density, + None, + None, + None, + occupancy_schedule) lighting = Lighting(lighting_density, lighting_convective_fraction, lighting_radiative_fraction, @@ -113,20 +139,12 @@ class NrcanCatalog(Catalog): appliances_radiative_fraction, appliances_latent_fraction, appliance_schedule) - if heating_schedule is not None: - thermal_control = ThermalControl(max(heating_schedule.values), - min(heating_schedule.values), - min(cooling_schedule.values), - None, - heating_schedule, - cooling_schedule) - else: - thermal_control = ThermalControl(None, - None, - None, - None, - None, - None) + thermal_control = ThermalControl(None, + None, + None, + hvac_availability, + heating_schedule, + cooling_schedule) hours_day = None days_year = None usages.append(Usage(usage_type, diff --git a/catalog_factories/usage/usage_helper.py b/catalog_factories/usage/usage_helper.py index 93c6fa04..d43af81f 100644 --- a/catalog_factories/usage/usage_helper.py +++ b/catalog_factories/usage/usage_helper.py @@ -19,6 +19,7 @@ class UsageHelper: 'Equipment': cte.APPLIANCES, 'Thermostat Setpoint Cooling': cte.COOLING_SET_POINT, # Compose 'Thermostat Setpoint' + 'Cooling' 'Thermostat Setpoint Heating': cte.HEATING_SET_POINT, # Compose 'Thermostat Setpoint' + 'Heating' + 'Fan': cte.HVAC_AVAILABILITY } _nrcan_data_type_to_hub_data_type = { 'FRACTION': cte.FRACTION, diff --git a/city_model_structure/building_demand/usage.py b/city_model_structure/building_demand/usage.py index 0a86b625..d6e4de77 100644 --- a/city_model_structure/building_demand/usage.py +++ b/city_model_structure/building_demand/usage.py @@ -26,7 +26,6 @@ class Usage: self._internal_gains = None self._hours_day = None self._days_year = None -# self._electrical_app_average_consumption_sqm_year = None self._mechanical_air_change = None self._occupancy = None self._lighting = None diff --git a/data/construction/nrcan.xml b/data/construction/nrcan.xml new file mode 100644 index 00000000..0a366273 --- /dev/null +++ b/data/construction/nrcan.xml @@ -0,0 +1,76 @@ + + + + + BTAPPRE1980/data/surface_thermal_transmittance.json + BTAPPRE1980/data/window_characteristics.json + + + BTAP1980TO2010/data/surface_thermal_transmittance.json + BTAP1980TO2010/data/window_characteristics.json + + + NECB2011/data/surface_thermal_transmittance.json + BTAP1980TO2010/data/window_characteristics.json + + + NECB2017/data/surface_thermal_transmittance.json + BTAP1980TO2010/data/window_characteristics.json + + + NECB2020/data/surface_thermal_transmittance.json + BTAP1980TO2010/data/window_characteristics.json + + + + + FullServiceRestaurant/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/8414706d-3ba9-4d70-ad3c-4db62d865e1b-os-report.html + + + HighriseApartment/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/83ab3764-046e-48a8-85cd-a3c0ac761efa-os-report.html + + + Hospital/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/210dac7e-2d51-40a9-bc78-ad0bc1c57a89-os-report.html + + + LargeHotel/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/d0185276-7fe0-4da9-bb5d-8c8a7c13c405-os-report.html + + + LargeOffice/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/2da33707-50a7-4554-91ed-c5fdbc1ce3b9-os-report.html + + + MediumOffice/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/65d97bf8-8749-410b-b53d-5a9c60e0227c-os-report.html + + + MidriseApartment/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/19518153-9c28-4e40-8bbd-98ef949c1bdb-os-report.html + + + Outpatient/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/deab93c7-d086-432d-bb90-33c8c4e1fab3-os-report.html + + + PrimarySchool/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/87f45397-5ef4-4df9-be41-d33c4b6d2fb7-os-report.html + + + QuickServiceRestaurant/CAN_PQ_Montreal.Intl.AP.716270_CWEC/ 0bc55858-a81b-4d07-9923-1d84e8a23194-os-report.html + + + RetailStandalone/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/a3643bcb-0eea-47d4-b6b9-253ed188ec0c-os-report.html + + + RetailStripmall/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/ebaf5a16-00af-49de-9672-6b373fc825be-os-report.html + + + SecondarySchool/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/3a4f105f-93ed-4b8b-9eb3-c8ca40c5de6e-os-report.html + + + SmallHotel/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/dff0a3fc-d9e5-4866-9e6a-dee9a0da60b2-os-report.html + + + SmallOffice/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/a9a3669d-beb8-4951-aa11-c27dbc61a344-os-report.html + + + Warehouse/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/569ec649-8017-4a3c-bd0a-337eba3ec488-os-report.html + + + diff --git a/data/usage/nrcan.xml b/data/usage/nrcan.xml index 5f160c9a..dfcbf90a 100644 --- a/data/usage/nrcan.xml +++ b/data/usage/nrcan.xml @@ -1,9 +1,5 @@ - - - NECB2020/data/space_types.json - NECB2015/data/schedules.json - - + NECB2020/data/space_types.json + NECB2015/data/schedules.json \ No newline at end of file diff --git a/imports/construction/helpers/construction_helper.py b/imports/construction/helpers/construction_helper.py index f29ba890..42709af7 100644 --- a/imports/construction/helpers/construction_helper.py +++ b/imports/construction/helpers/construction_helper.py @@ -23,6 +23,7 @@ class ConstructionHelper: cte.SMALL_OFFICE: 'small office', cte.MEDIUM_OFFICE: 'medium office', cte.LARGE_OFFICE: 'large office', + cte.EDUCATION: 'primary school', cte.PRIMARY_SCHOOL: 'primary school', cte.SECONDARY_SCHOOL: 'secondary school', cte.STAND_ALONE_RETAIL: 'stand-alone retail', diff --git a/imports/construction/nrcan_physics_parameters.py b/imports/construction/nrcan_physics_parameters.py new file mode 100644 index 00000000..258673db --- /dev/null +++ b/imports/construction/nrcan_physics_parameters.py @@ -0,0 +1,188 @@ +""" +NrcanPhysicsParameters import the construction and material information defined by NRCAN +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca +""" +import sys + +from catalog_factories.construction_catalog_factory import ConstructionCatalogFactory +from city_model_structure.building_demand.layer import Layer +from city_model_structure.building_demand.material import Material +from imports.construction.helpers.construction_helper import ConstructionHelper +from imports.construction.helpers.storeys_generation import StoreysGeneration + + +class NrcanPhysicsParameters: + """ + NrcanPhysicsParameters class + """ + def __init__(self, city, base_path, divide_in_storeys=False): + self._city = city + self._path = base_path + self._divide_in_storeys = divide_in_storeys + self._climate_zone = ConstructionHelper.city_to_nrel_climate_zone(city.name) + + def enrich_buildings(self): + """ + Returns the city with the construction parameters assigned to the buildings + """ + city = self._city + canel_catalog = ConstructionCatalogFactory('nrcan').catalog + for building in city.buildings: + try: + function = ConstructionHelper().nrel_from_libs_function(building.function) + archetype = self._search_archetype(canel_catalog, function, building.year_of_construction, + self._climate_zone) + except KeyError: + sys.stderr.write(f'Building {building.name} has unknown construction archetype for building function: ' + f'{building.function} and building year of construction: {building.year_of_construction} ' + f'and climate zone reference norm {self._climate_zone}\n') + return + + # if building has no thermal zones defined from geometry, and the building will be divided in storeys, + # one thermal zone per storey is assigned + if len(building.internal_zones) == 1: + if building.internal_zones[0].thermal_zones is None: + self._create_storeys(building, archetype, self._divide_in_storeys) + if self._divide_in_storeys: + for internal_zone in building.internal_zones: + for thermal_zone in internal_zone.thermal_zones: + thermal_zone.total_floor_area = thermal_zone.footprint_area + else: + number_of_storeys = int(float(building.eave_height) / float(building.average_storey_height)) + thermal_zone = building.internal_zones[0].thermal_zones[0] + thermal_zone.total_floor_area = thermal_zone.footprint_area * number_of_storeys + else: + for internal_zone in building.internal_zones: + for thermal_zone in internal_zone.thermal_zones: + thermal_zone.total_floor_area = thermal_zone.footprint_area + + for internal_zone in building.internal_zones: + self._assign_values(internal_zone.thermal_zones, archetype) + for thermal_zone in internal_zone.thermal_zones: + self._calculate_view_factors(thermal_zone) + + @staticmethod + def _search_archetype(nrel_catalog, function, year_of_construction, climate_zone): + nrel_archetypes = nrel_catalog.entries('archetypes') + for building_archetype in nrel_archetypes: + construction_period_limits = building_archetype.construction_period.split(' - ') + if construction_period_limits[1] == 'PRESENT': + construction_period_limits[1] = 3000 + if int(construction_period_limits[0]) <= int(year_of_construction) < int(construction_period_limits[1]): + if (str(function) == str(building_archetype.function)) and \ + (climate_zone == str(building_archetype.climate_zone)): + return building_archetype + raise KeyError('archetype not found') + + @staticmethod + def _search_construction_in_archetype(archetype, construction_type): + construction_archetypes = archetype.constructions + for construction_archetype in construction_archetypes: + if str(construction_type) == str(construction_archetype.type): + return construction_archetype + return None + + def _assign_values(self, thermal_zones, archetype): + for thermal_zone in thermal_zones: + thermal_zone.additional_thermal_bridge_u_value = archetype.extra_loses_due_to_thermal_bridges + thermal_zone.effective_thermal_capacity = archetype.thermal_capacity + thermal_zone.indirectly_heated_area_ratio = archetype.indirect_heated_ratio + thermal_zone.infiltration_rate_system_on = archetype.infiltration_rate_for_ventilation_system_on + thermal_zone.infiltration_rate_system_off = archetype.infiltration_rate_for_ventilation_system_off + for thermal_boundary in thermal_zone.thermal_boundaries: + construction_archetype = self._search_construction_in_archetype(archetype, thermal_boundary.type) + thermal_boundary.construction_name = construction_archetype.name + try: + thermal_boundary.window_ratio = construction_archetype.window_ratio + except ValueError: + # This is the normal operation way when the windows are defined in the geometry + continue + thermal_boundary.layers = [] + for layer_archetype in construction_archetype.layers: + layer = Layer() + layer.thickness = layer_archetype.thickness + material = Material() + archetype_material = layer_archetype.material + material.name = archetype_material.name + material.id = archetype_material.id + material.no_mass = archetype_material.no_mass + if archetype_material.no_mass: + material.thermal_resistance = archetype_material.thermal_resistance + else: + material.density = archetype_material.density + material.conductivity = archetype_material.conductivity + material.specific_heat = archetype_material.specific_heat + material.solar_absorptance = archetype_material.solar_absorptance + material.thermal_absorptance = archetype_material.thermal_absorptance + material.visible_absorptance = archetype_material.visible_absorptance + layer.material = material + thermal_boundary.layers.append(layer) + # The agreement is that the layers are defined from outside to inside + external_layer = construction_archetype.layers[0] + external_surface = thermal_boundary.parent_surface + external_surface.short_wave_reflectance = 1 - float(external_layer.material.solar_absorptance) + external_surface.long_wave_emittance = 1 - float(external_layer.material.solar_absorptance) + internal_layer = construction_archetype.layers[len(construction_archetype.layers) - 1] + internal_surface = thermal_boundary.internal_surface + internal_surface.short_wave_reflectance = 1 - float(internal_layer.material.solar_absorptance) + internal_surface.long_wave_emittance = 1 - float(internal_layer.material.solar_absorptance) + + for thermal_opening in thermal_boundary.thermal_openings: + if construction_archetype.window is not None: + window_archetype = construction_archetype.window + thermal_opening.construction_name = window_archetype.name + thermal_opening.frame_ratio = window_archetype.frame_ratio + thermal_opening.g_value = window_archetype.g_value + thermal_opening.overall_u_value = window_archetype.overall_u_value + + # todo: verify windows + @staticmethod + def _calculate_view_factors(thermal_zone): + """ + Get thermal zone view factors matrix + :return: [[float]] + """ + total_area = 0 + for thermal_boundary in thermal_zone.thermal_boundaries: + total_area += thermal_boundary.opaque_area + for thermal_opening in thermal_boundary.thermal_openings: + total_area += thermal_opening.area + + view_factors_matrix = [] + for thermal_boundary_1 in thermal_zone.thermal_boundaries: + values = [] + for thermal_boundary_2 in thermal_zone.thermal_boundaries: + value = 0 + if thermal_boundary_1.id != thermal_boundary_2.id: + value = thermal_boundary_2.opaque_area / (total_area - thermal_boundary_1.opaque_area) + values.append(value) + for thermal_boundary in thermal_zone.thermal_boundaries: + for thermal_opening in thermal_boundary.thermal_openings: + value = thermal_opening.area / (total_area - thermal_boundary_1.opaque_area) + values.append(value) + view_factors_matrix.append(values) + + for thermal_boundary_1 in thermal_zone.thermal_boundaries: + values = [] + for thermal_opening_1 in thermal_boundary_1.thermal_openings: + for thermal_boundary_2 in thermal_zone.thermal_boundaries: + value = thermal_boundary_2.opaque_area / (total_area - thermal_opening_1.area) + values.append(value) + for thermal_boundary in thermal_zone.thermal_boundaries: + for thermal_opening_2 in thermal_boundary.thermal_openings: + value = 0 + if thermal_opening_1.id != thermal_opening_2.id: + value = thermal_opening_2.area / (total_area - thermal_opening_1.area) + values.append(value) + view_factors_matrix.append(values) + thermal_zone.view_factors_matrix = view_factors_matrix + + @staticmethod + def _create_storeys(building, archetype, divide_in_storeys): + building.average_storey_height = archetype.average_storey_height + building.storeys_above_ground = 1 + thermal_zones = StoreysGeneration(building, building.internal_zones[0], + divide_in_storeys=divide_in_storeys).thermal_zones + building.internal_zones[0].thermal_zones = thermal_zones diff --git a/imports/construction/nrel_physics_parameters.py b/imports/construction/nrel_physics_parameters.py index 20576519..2ed1c097 100644 --- a/imports/construction/nrel_physics_parameters.py +++ b/imports/construction/nrel_physics_parameters.py @@ -32,7 +32,8 @@ class NrelPhysicsParameters: nrel_catalog = ConstructionCatalogFactory('nrel').catalog for building in city.buildings: try: - archetype = self._search_archetype(nrel_catalog, building.function, building.year_of_construction, + function = ConstructionHelper().nrel_from_libs_function(building.function) + archetype = self._search_archetype(nrel_catalog, function, building.year_of_construction, self._climate_zone) except KeyError: sys.stderr.write(f'Building {building.name} has unknown construction archetype for building function: ' diff --git a/imports/construction_factory.py b/imports/construction_factory.py index acf35988..4bf1110f 100644 --- a/imports/construction_factory.py +++ b/imports/construction_factory.py @@ -3,14 +3,17 @@ ConstructionFactory (before PhysicsFactory) retrieve the specific construction m 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 imports.construction.nrel_physics_parameters import NrelPhysicsParameters +from imports.construction.nrcan_physics_parameters import NrcanPhysicsParameters class ConstructionFactory: """ - PhysicsFactor class + ConstructionFactory class """ def __init__(self, handler, city, base_path=None): if base_path is None: @@ -26,6 +29,13 @@ class ConstructionFactory: NrelPhysicsParameters(self._city, self._base_path).enrich_buildings() self._city.level_of_detail.construction = 2 + def _nrcan(self): + """ + Enrich the city by using NRCAN information + """ + NrcanPhysicsParameters(self._city, self._base_path).enrich_buildings() + self._city.level_of_detail.construction = 2 + def enrich(self): """ Enrich the city given to the class using the class given handler diff --git a/imports/usage/comnet_usage_parameters.py b/imports/usage/comnet_usage_parameters.py index c84e9c32..b5bfb8cc 100644 --- a/imports/usage/comnet_usage_parameters.py +++ b/imports/usage/comnet_usage_parameters.py @@ -120,6 +120,31 @@ class ComnetUsageParameters: usage_zone.hours_day = total / 365 usage_zone.days_year = 365 + max_heating_setpoint = cte.MIN_FLOAT + min_heating_setpoint = cte.MAX_FLOAT + + for schedule in archetype.thermal_control.heating_set_point_schedules: + if schedule.values is None: + max_heating_setpoint = None + min_heating_setpoint = None + break + if max(schedule.values) > max_heating_setpoint: + max_heating_setpoint = max(schedule.values) + if min(schedule.values) < min_heating_setpoint: + min_heating_setpoint = min(schedule.values) + + min_cooling_setpoint = cte.MAX_FLOAT + for schedule in archetype.thermal_control.cooling_set_point_schedules: + if schedule.values is None: + min_cooling_setpoint = None + break + if min(schedule.values) < min_cooling_setpoint: + min_cooling_setpoint = min(schedule.values) + + usage_zone.thermal_control.mean_heating_set_point = max_heating_setpoint + usage_zone.thermal_control.heating_set_back = min_heating_setpoint + usage_zone.thermal_control.mean_cooling_set_point = min_cooling_setpoint + @staticmethod def _calculate_internal_gains(archetype): diff --git a/imports/usage/helpers/usage_helper.py b/imports/usage/helpers/usage_helper.py index b1ae610a..eece9580 100644 --- a/imports/usage/helpers/usage_helper.py +++ b/imports/usage/helpers/usage_helper.py @@ -131,9 +131,9 @@ class UsageHelper: 'done changing the keywords.\n') _usage_to_nrcan = { - cte.RESIDENTIAL: 'Multi-unit residential', - cte.SINGLE_FAMILY_HOUSE: 'Multi-unit residential', - cte.MULTI_FAMILY_HOUSE: 'Multi-unit residential', + cte.RESIDENTIAL: 'Multi-unit residential building', + cte.SINGLE_FAMILY_HOUSE: 'Multi-unit residential building', + cte.MULTI_FAMILY_HOUSE: 'Multi-unit residential building', cte.EDUCATION: 'School/university', cte.SCHOOL_WITHOUT_SHOWER: 'School/university', cte.SCHOOL_WITH_SHOWER: 'School/university', @@ -145,7 +145,7 @@ class UsageHelper: cte.INDUSTRY: 'Manufacturing Facility', cte.RESTAURANT: 'Dining - family', cte.HEALTH_CARE: 'Hospital', - cte.RETIREMENT_HOME_OR_ORPHANAGE: 'Multi-unit residential', + cte.RETIREMENT_HOME_OR_ORPHANAGE: 'Multi-unit residential building', cte.OFFICE_AND_ADMINISTRATION: 'Office', cte.EVENT_LOCATION: 'Convention centre', cte.HALL: 'Convention centre', diff --git a/imports/usage/nrcan_usage_parameters.py b/imports/usage/nrcan_usage_parameters.py index ea2b1a4b..92acfb65 100644 --- a/imports/usage/nrcan_usage_parameters.py +++ b/imports/usage/nrcan_usage_parameters.py @@ -4,9 +4,8 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2022 Concordia CERC group Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca """ -import copy + import sys -import numpy import helpers.constants as cte from imports.usage.helpers.usage_helper import UsageHelper @@ -15,8 +14,6 @@ from city_model_structure.building_demand.lighting import Lighting from city_model_structure.building_demand.occupancy import Occupancy from city_model_structure.building_demand.appliances import Appliances from city_model_structure.building_demand.thermal_control import ThermalControl -from city_model_structure.attributes.schedule import Schedule -from city_model_structure.building_demand.internal_gain import InternalGain from catalog_factories.usage_catalog_factory import UsageCatalogFactory @@ -35,6 +32,7 @@ class NrcanUsageParameters: """ city = self._city nrcan_catalog = UsageCatalogFactory('nrcan').catalog + comnet_catalog = UsageCatalogFactory('comnet').catalog for building in city.buildings: usage_name = UsageHelper.nrcan_from_hub_usage(building.function) @@ -45,6 +43,14 @@ class NrcanUsageParameters: f' {building.function}') return + usage_name = UsageHelper.comnet_from_hub_usage(building.function) + try: + comnet_archetype_usage = self._search_archetypes(comnet_catalog, usage_name) + except KeyError: + sys.stderr.write(f'Building {building.name} has unknown usage archetype for building function:' + f' {building.function}') + return + for internal_zone in building.internal_zones: if internal_zone.area is None: raise Exception('Internal zone area not defined, ACH cannot be calculated') @@ -56,24 +62,22 @@ class NrcanUsageParameters: usage_zone = Usage() usage_zone.name = usage_name self._assign_values(usage_zone, archetype_usage, volume_per_area) + self._assign_comnet_extra_values(usage_zone, comnet_archetype_usage) usage_zone.percentage = 1 self._calculate_reduced_values_from_extended_library(usage_zone, archetype_usage) internal_zone.usages = [usage_zone] @staticmethod - def _search_archetypes(comnet_catalog, usage_name): - comnet_archetypes = comnet_catalog.entries('archetypes').usages - for building_archetype in comnet_archetypes: + def _search_archetypes(catalog, usage_name): + archetypes = catalog.entries('archetypes').usages + for building_archetype in archetypes: if str(usage_name) == str(building_archetype.name): return building_archetype raise KeyError('archetype not found') @staticmethod def _assign_values(usage_zone, archetype, volume_per_area): - # Due to the fact that python is not a typed language, the wrong object type is assigned to - # usage_zone.occupancy when writing usage_zone.occupancy = archetype.occupancy. - # Same happens for lighting and appliances. Therefore, this walk around has been done. if archetype.mechanical_air_change > 0: usage_zone.mechanical_air_change = archetype.mechanical_air_change elif archetype.ventilation_rate > 0: @@ -86,7 +90,7 @@ class NrcanUsageParameters: _occupancy.sensible_radiative_internal_gain = archetype.occupancy.sensible_radiative_internal_gain _occupancy.latent_internal_gain = archetype.occupancy.latent_internal_gain _occupancy.sensible_convective_internal_gain = archetype.occupancy.sensible_convective_internal_gain - _occupancy.occupancy_schedules = archetype.occupancy.occupancy_schedules + _occupancy.occupancy_schedules = archetype.occupancy.schedules usage_zone.occupancy = _occupancy _lighting = Lighting() _lighting.density = archetype.lighting.density @@ -108,6 +112,13 @@ class NrcanUsageParameters: _control.hvac_availability_schedules = archetype.thermal_control.hvac_availability_schedules usage_zone.thermal_control = _control + @staticmethod + def _assign_comnet_extra_values(usage_zone, archetype): + _occupancy = usage_zone.occupancy + _occupancy.sensible_radiative_internal_gain = archetype.occupancy.sensible_radiative_internal_gain + _occupancy.latent_internal_gain = archetype.occupancy.latent_internal_gain + _occupancy.sensible_convective_internal_gain = archetype.occupancy.sensible_convective_internal_gain + @staticmethod def _calculate_reduced_values_from_extended_library(usage_zone, archetype): number_of_days_per_type = {'WD': 251, 'Sat': 52, 'Sun': 62} @@ -126,66 +137,27 @@ class NrcanUsageParameters: usage_zone.hours_day = total / 365 usage_zone.days_year = 365 - @staticmethod - def _calculate_internal_gains(archetype): + max_heating_setpoint = cte.MIN_FLOAT + min_heating_setpoint = cte.MAX_FLOAT - _DAYS = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY, cte.SATURDAY, cte.SUNDAY, cte.HOLIDAY] - _number_of_days_per_type = [51, 50, 50, 50, 50, 52, 52, 10] + for schedule in archetype.thermal_control.heating_set_point_schedules: + if schedule.values is None: + max_heating_setpoint = None + min_heating_setpoint = None + break + if max(schedule.values) > max_heating_setpoint: + max_heating_setpoint = max(schedule.values) + if min(schedule.values) < min_heating_setpoint: + min_heating_setpoint = min(schedule.values) - _mean_internal_gain = InternalGain() - _mean_internal_gain.type = 'mean_value_of_internal_gains' - _base_schedule = Schedule() - _base_schedule.type = cte.INTERNAL_GAINS - _base_schedule.time_range = cte.DAY - _base_schedule.time_step = cte.HOUR - _base_schedule.data_type = cte.FRACTION + min_cooling_setpoint = cte.MAX_FLOAT + for schedule in archetype.thermal_control.cooling_set_point_schedules: + if schedule.values is None: + min_cooling_setpoint = None + break + if min(schedule.values) < min_cooling_setpoint: + min_cooling_setpoint = min(schedule.values) - _latent_heat_gain = archetype.occupancy.latent_internal_gain - _convective_heat_gain = archetype.occupancy.sensible_convective_internal_gain - _radiative_heat_gain = archetype.occupancy.sensible_radiative_internal_gain - _total_heat_gain = (_latent_heat_gain + _convective_heat_gain + _radiative_heat_gain) - - _schedule_values = numpy.zeros([24, 8]) - _sum = 0 - for day, _schedule in enumerate(archetype.occupancy.schedules): - for v, value in enumerate(_schedule.values): - _schedule_values[v, day] = value * _total_heat_gain - _sum += value * _total_heat_gain * _number_of_days_per_type[day] - - _total_heat_gain += archetype.lighting.density + archetype.appliances.density - _latent_heat_gain += archetype.lighting.latent_fraction * archetype.lighting.density\ - + archetype.appliances.latent_fraction * archetype.appliances.density - _radiative_heat_gain = archetype.lighting.radiative_fraction * archetype.lighting.density \ - + archetype.appliances.radiative_fraction * archetype.appliances.density - _convective_heat_gain = archetype.lighting.convective_fraction * archetype.lighting.density \ - + archetype.appliances.convective_fraction * archetype.appliances.density - - for day, _schedule in enumerate(archetype.lighting.schedules): - for v, value in enumerate(_schedule.values): - _schedule_values[v, day] += value * archetype.lighting.density - _sum += value * archetype.lighting.density * _number_of_days_per_type[day] - - for day, _schedule in enumerate(archetype.appliances.schedules): - for v, value in enumerate(_schedule.values): - _schedule_values[v, day] += value * archetype.appliances.density - _sum += value * archetype.appliances.density * _number_of_days_per_type[day] - - _latent_fraction = _latent_heat_gain / _total_heat_gain - _radiative_fraction = _radiative_heat_gain / _total_heat_gain - _convective_fraction = _convective_heat_gain / _total_heat_gain - _average_internal_gain = _sum / _total_heat_gain - - _schedules = [] - for day in range(0, len(_DAYS)): - _schedule = copy.deepcopy(_base_schedule) - _schedule.day_types = [_DAYS[day]] - _schedule.values = _schedule_values[:day] - _schedules.append(_schedule) - - _mean_internal_gain.average_internal_gain = _average_internal_gain - _mean_internal_gain.latent_fraction = _latent_fraction - _mean_internal_gain.convective_fraction = _convective_fraction - _mean_internal_gain.radiative_fraction = _radiative_fraction - _mean_internal_gain.schedules = _schedules - - return [_mean_internal_gain] + usage_zone.thermal_control.mean_heating_set_point = max_heating_setpoint + usage_zone.thermal_control.heating_set_back = min_heating_setpoint + usage_zone.thermal_control.mean_cooling_set_point = min_cooling_setpoint diff --git a/unittests/test_enrichement.py b/unittests/test_enrichement.py index c63922f2..e9d3b9ca 100644 --- a/unittests/test_enrichement.py +++ b/unittests/test_enrichement.py @@ -86,11 +86,12 @@ class TestGeometryFactory(TestCase): elif input_key == 'hft': for building in city.buildings: building.function = GeometryHelper.libs_function_from_hft(building.function) + print(construction_key, usage_key) ConstructionFactory(construction_key, city).enrich() UsageFactory(usage_key, city).enrich() def _test_hft(self, file): - _construction_keys = ['nrel'] + _construction_keys = ['nrcan', 'nrel'] _usage_keys = ['comnet', 'nrcan'] for construction_key in _construction_keys: for usage_key in _usage_keys: @@ -121,7 +122,7 @@ class TestGeometryFactory(TestCase): def _test_pluto(self, file): _construction_keys = ['nrel'] - _usage_keys = ['comnet', 'hft'] + _usage_keys = ['comnet', 'nrcan'] for construction_key in _construction_keys: for usage_key in _usage_keys: # construction factory called first From 2ffbf06ac5f0b01691a3be8a690c2820ba7f5be2 Mon Sep 17 00:00:00 2001 From: Pilar Date: Fri, 16 Dec 2022 07:21:33 -0500 Subject: [PATCH 6/8] centralized all dictionaries in helpers.dictionaries.py and reviewed all those from hub to something --- .../construction/construction_helper.py | 45 +- .../construction/nrel_catalog.py | 2 +- catalog_factories/usage/usage_helper.py | 74 --- city_model_structure/city.py | 1 - helpers/constants.py | 63 +- helpers/dictionaries.py | 595 ++++++++++++++++++ .../helpers/construction_helper.py | 41 +- .../construction/nrcan_physics_parameters.py | 3 +- .../construction/nrel_physics_parameters.py | 4 +- imports/geometry/citygml.py | 4 - .../geometry/citygml_classes/citygml_base.py | 2 - imports/geometry/helpers/geometry_helper.py | 275 -------- imports/usage/comnet_usage_parameters.py | 4 +- imports/usage/helpers/schedules_helper.py | 87 --- imports/usage/helpers/usage_helper.py | 169 ----- imports/usage/nrcan_usage_parameters.py | 6 +- unittests/test_construction_factory.py | 12 +- unittests/test_enrichement.py | 12 +- unittests/test_exports.py | 4 +- unittests/test_usage_catalog.py | 2 +- unittests/test_usage_factory.py | 4 +- 21 files changed, 682 insertions(+), 727 deletions(-) create mode 100644 helpers/dictionaries.py delete mode 100644 imports/usage/helpers/schedules_helper.py delete mode 100644 imports/usage/helpers/usage_helper.py diff --git a/catalog_factories/construction/construction_helper.py b/catalog_factories/construction/construction_helper.py index 3708fbd0..aedfe460 100644 --- a/catalog_factories/construction/construction_helper.py +++ b/catalog_factories/construction/construction_helper.py @@ -5,39 +5,13 @@ class ConstructionHelper: """ Construction helper class """ - nrel_to_function = { - 'residential': cte.RESIDENTIAL, - 'midrise apartment': cte.MID_RISE_APARTMENT, - 'high-rise apartment': cte.HIGH_RISE_APARTMENT, - 'small office': cte.SMALL_OFFICE, - 'medium office': cte.MEDIUM_OFFICE, - 'large office': cte.LARGE_OFFICE, - 'primary school': cte.PRIMARY_SCHOOL, - 'secondary school': cte.SECONDARY_SCHOOL, - 'stand-alone retail': cte.STAND_ALONE_RETAIL, - 'hospital': cte.HOSPITAL, - 'outpatient healthcare': cte.OUT_PATIENT_HEALTH_CARE, - 'strip mall': cte.STRIP_MALL, - 'supermarket': cte.SUPERMARKET, - 'warehouse': cte.WAREHOUSE, - 'quick service restaurant': cte.QUICK_SERVICE_RESTAURANT, - 'full service restaurant': cte.FULL_SERVICE_RESTAURANT, - 'small hotel': cte.SMALL_HOTEL, - 'large hotel': cte.LARGE_HOTEL, - 'industry': cte.INDUSTRY - } - - nrcan_to_function = { - 'residential': cte.RESIDENTIAL, - } - - reference_standard_to_construction_period = { + _reference_standard_to_construction_period = { 'non_standard_dompark': '1900 - 2004', 'ASHRAE 90.1_2004': '2004 - 2009', 'ASHRAE 189.1_2009': '2009 - PRESENT' } - nrel_surfaces_types_to_hub_types = { + _nrel_surfaces_types_to_hub_types = { 'exterior wall': cte.WALL, 'interior wall': cte.INTERIOR_WALL, 'ground wall': cte.GROUND_WALL, @@ -46,7 +20,8 @@ class ConstructionHelper: 'interior slab': cte.INTERIOR_SLAB, 'roof': cte.ROOF } - nrcan_surfaces_types_to_hub_types = { + + _nrcan_surfaces_types_to_hub_types = { 'Wall_Outdoors': cte.WALL, 'RoofCeiling_Outdoors': cte.ROOF, 'Floor_Outdoors': cte.ATTIC_FLOOR, @@ -57,3 +32,15 @@ class ConstructionHelper: 'RoofCeiling_Ground': cte.GROUND_WALL, 'Floor_Ground': cte.GROUND } + + @property + def reference_standard_to_construction_period(self): + return self._reference_standard_to_construction_period + + @property + def nrel_surfaces_types_to_hub_types(self): + return self._nrel_surfaces_types_to_hub_types + + @property + def nrcan_surfaces_types_to_hub_types(self): + return self._nrcan_surfaces_types_to_hub_types diff --git a/catalog_factories/construction/nrel_catalog.py b/catalog_factories/construction/nrel_catalog.py index f286ff9a..e1b5711c 100644 --- a/catalog_factories/construction/nrel_catalog.py +++ b/catalog_factories/construction/nrel_catalog.py @@ -109,7 +109,7 @@ class NrelCatalog(Catalog): archetypes = self._archetypes['archetypes']['archetype'] for archetype in archetypes: archetype_id = archetype['@id'] - function = ConstructionHelper().nrel_to_function[archetype['@building_type']] + function = archetype['@building_type'] name = f"{function} {archetype['@climate_zone']} {archetype['@reference_standard']}" climate_zone = archetype['@climate_zone'] construction_period = \ diff --git a/catalog_factories/usage/usage_helper.py b/catalog_factories/usage/usage_helper.py index d43af81f..630f6207 100644 --- a/catalog_factories/usage/usage_helper.py +++ b/catalog_factories/usage/usage_helper.py @@ -59,31 +59,6 @@ class UsageHelper: } - _usage_to_hft = { - cte.RESIDENTIAL: 'residential', - cte.SINGLE_FAMILY_HOUSE: 'Single family house', - cte.MULTI_FAMILY_HOUSE: 'Multi-family house', - cte.EDUCATION: 'education', - cte.SCHOOL_WITHOUT_SHOWER: 'school without shower', - cte.SCHOOL_WITH_SHOWER: 'school with shower', - cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'retail', - cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'retail shop / refrigerated food', - cte.HOTEL: 'hotel', - cte.HOTEL_MEDIUM_CLASS: 'hotel (Medium-class)', - cte.DORMITORY: 'dormitory', - cte.INDUSTRY: 'industry', - cte.RESTAURANT: 'restaurant', - cte.HEALTH_CARE: 'health care', - cte.RETIREMENT_HOME_OR_ORPHANAGE: 'Home for the aged or orphanage', - cte.OFFICE_AND_ADMINISTRATION: 'office and administration', - cte.EVENT_LOCATION: 'event location', - cte.HALL: 'hall', - cte.SPORTS_LOCATION: 'sport location', - cte.LABOR: 'Labor', - cte.GREEN_HOUSE: 'green house', - cte.NON_HEATED: 'non-heated' - } - _comnet_days = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, @@ -93,31 +68,6 @@ class UsageHelper: cte.SUNDAY, cte.HOLIDAY] - _usage_to_comnet = { - cte.RESIDENTIAL: 'BA Multifamily', - cte.SINGLE_FAMILY_HOUSE: 'BA Multifamily', - cte.MULTI_FAMILY_HOUSE: 'BA Multifamily', - cte.EDUCATION: 'BA School/University', - cte.SCHOOL_WITHOUT_SHOWER: 'BA School/University', - cte.SCHOOL_WITH_SHOWER: 'BA School/University', - cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'BA Retail', - cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'BA Retail', - cte.HOTEL: 'BA Hotel', - cte.HOTEL_MEDIUM_CLASS: 'BA Hotel', - cte.DORMITORY: 'BA Dormitory', - cte.INDUSTRY: 'BA Manufacturing Facility', - cte.RESTAURANT: 'BA Dining: Family', - cte.HEALTH_CARE: 'BA Hospital', - cte.RETIREMENT_HOME_OR_ORPHANAGE: 'BA Multifamily', - cte.OFFICE_AND_ADMINISTRATION: 'BA Office', - cte.EVENT_LOCATION: 'BA Convention Center', - cte.HALL: 'BA Convention Center', - cte.SPORTS_LOCATION: 'BA Sports Arena', - cte.LABOR: 'BA Gymnasium', - cte.GREEN_HOUSE: cte.GREEN_HOUSE, - cte.NON_HEATED: cte.NON_HEATED - } - _comnet_data_type_to_hub_data_type = { 'Fraction': cte.FRACTION, 'OnOff': cte.ON_OFF, @@ -167,18 +117,6 @@ class UsageHelper: def comnet_days(self): return self._comnet_days - @staticmethod - def comnet_from_hub_usage(usage): - """ - Get Comnet usage from the given internal usage key - :param usage: str - :return: str - """ - try: - return UsageHelper._usage_to_comnet[usage] - except KeyError: - sys.stderr.write('Error: keyword not found to translate from hub_usage to comnet usage.\n') - @staticmethod def schedules_key(usage): """ @@ -191,15 +129,3 @@ class UsageHelper: except KeyError: sys.stderr.write('Error: Comnet keyword not found. An update of the Comnet files might have been ' 'done changing the keywords.\n') - - @staticmethod - def hft_from_hub_usage(usage): - """ - Get HfT usage from the given internal usage key - :param usage: str - :return: str - """ - try: - return UsageHelper._usage_to_hft[usage] - except KeyError: - sys.stderr.write('Error: keyword not found to translate from hub_usage to hft usage.\n') diff --git a/city_model_structure/city.py b/city_model_structure/city.py index 39e9736c..8871a41d 100644 --- a/city_model_structure/city.py +++ b/city_model_structure/city.py @@ -43,7 +43,6 @@ class City: self._buildings = None self._subway_entrances = None self._srs_name = srs_name - self._geometry = GeometryHelper() # todo: right now extracted at city level, in the future should be extracted also at building level if exist self._location = None self._country_code = None diff --git a/helpers/constants.py b/helpers/constants.py index 77710265..479c9dd5 100644 --- a/helpers/constants.py +++ b/helpers/constants.py @@ -66,45 +66,64 @@ DOOR = 'Door' SKYLIGHT = 'Skylight' # functions and usages +RESIDENTIAL = 'residential' SINGLE_FAMILY_HOUSE = 'single family house' MULTI_FAMILY_HOUSE = 'multifamily house' -ROW_HOSE = 'row house' +ROW_HOUSE = 'row house' MID_RISE_APARTMENT = 'mid rise apartment' HIGH_RISE_APARTMENT = 'high rise apartment' +OFFICE_AND_ADMINISTRATION = 'office and administration' SMALL_OFFICE = 'small office' MEDIUM_OFFICE = 'medium office' LARGE_OFFICE = 'large office' +COURTHOUSE = 'courthouse' +FIRE_STATION = 'fire station' +PENITENTIARY = 'penitentiary' +POLICE_STATION = 'police station' +POST_OFFICE = 'post office' +LIBRARY = 'library' +EDUCATION = 'education' PRIMARY_SCHOOL = 'primary school' +PRIMARY_SCHOOL_WITH_SHOWER = 'school with shower' SECONDARY_SCHOOL = 'secondary school' +UNIVERSITY = 'university' +LABORATORY_AND_RESEARCH_CENTER = 'laboratory and research centers' STAND_ALONE_RETAIL = 'stand alone retail' HOSPITAL = 'hospital' OUT_PATIENT_HEALTH_CARE = 'out-patient health care' -STRIP_MALL = 'strip mall' -SUPERMARKET = 'supermarket' -WAREHOUSE = 'warehouse' -QUICK_SERVICE_RESTAURANT = 'quick service restaurant' -FULL_SERVICE_RESTAURANT = 'full service restaurant' -SMALL_HOTEL = 'small hotel' -LARGE_HOTEL = 'large hotel' -RESIDENTIAL = 'residential' -EDUCATION = 'education' -SCHOOL_WITHOUT_SHOWER = 'school without shower' -SCHOOL_WITH_SHOWER = 'school with shower' -RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD = 'retail shop without refrigerated food' -RETAIL_SHOP_WITH_REFRIGERATED_FOOD = 'retail shop with refrigerated food' -HOTEL = 'hotel' -HOTEL_MEDIUM_CLASS = 'hotel medium class' -DORMITORY = 'dormitory' -INDUSTRY = 'industry' -RESTAURANT = 'restaurant' HEALTH_CARE = 'health care' RETIREMENT_HOME_OR_ORPHANAGE = 'retirement home or orphanage' -OFFICE_AND_ADMINISTRATION = 'office and administration' +COMMERCIAL = 'commercial' +STRIP_MALL = 'strip mall' +SUPERMARKET = 'supermarket' +RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD = 'retail shop without refrigerated food' +RETAIL_SHOP_WITH_REFRIGERATED_FOOD = 'retail shop with refrigerated food' +RESTAURANT = 'restaurant' +QUICK_SERVICE_RESTAURANT = 'quick service restaurant' +FULL_SERVICE_RESTAURANT = 'full service restaurant' +HOTEL = 'hotel' +HOTEL_MEDIUM_CLASS = 'hotel medium class' +SMALL_HOTEL = 'small hotel' +LARGE_HOTEL = 'large hotel' +DORMITORY = 'dormitory' EVENT_LOCATION = 'event location' +CONVENTION_CENTER = 'convention center' HALL = 'hall' -SPORTS_LOCATION = 'sports location' -LABOR = 'labor' GREEN_HOUSE = 'green house' +INDUSTRY = 'industry' +WORKSHOP = 'workshop' +WAREHOUSE = 'warehouse' +WAREHOUSE_REFRIGERATED = 'warehouse refrigerated' +SPORTS_LOCATION = 'sports location' +SPORTS_ARENA = 'sports arena' +GYMNASIUM = 'gymnasium' +MOTION_PICTURE_THEATRE = 'motion picture theatre' +MUSEUM = 'museum' +PERFORMING_ARTS_THEATRE = 'performing arts theatre' +TRANSPORTATION = 'transportation' +AUTOMOTIVE_FACILITY = 'automotive facility' +PARKING_GARAGE = 'parking garage' +RELIGIOUS = 'religious' NON_HEATED = 'non-heated' LIGHTING = 'Lights' diff --git a/helpers/dictionaries.py b/helpers/dictionaries.py new file mode 100644 index 00000000..f9bd37ac --- /dev/null +++ b/helpers/dictionaries.py @@ -0,0 +1,595 @@ +""" +Dictionaries module saves all transformations of functions and usages to access the catalogs +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca +""" + +import helpers.constants as cte + + +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): + """ + Get HfT usage from the given internal usage + :return: dict + """ + return self._usage_to_hft_usage + + @property + def hub_usage_to_comnet_usage(self): + """ + Get Comnet usage from the given internal usage + :return: dict + """ + return self._usage_to_comnet_usage + + @property + def hub_usage_to_nrcan_usage(self): + """ + Get Nrcan usage from the given internal usage + :return: dict + """ + return self._usage_to_nrcan_usage + + @property + def hub_function_to_nrcan_construction_function(self): + """ + Get Nrcan construction function from the given internal function + :return: dict + """ + return self._function_to_nrcan_construction_function + + @property + def hub_function_to_nrel_construction_function(self): + """ + Get Nrel construction function from the given internal function + :return: dict + """ + return self._function_to_nrel_construction_function + + @property + def pluto_function_to_hub_function(self): + """ + Set internal function from pluto standard + :return: dict + """ + return self._pluto_function_to_hub_function + + @property + def hft_function_to_hub_function(self): + """ + Set internal function from functions used in hft files + :return: dict + """ + return self._hft_function_to_hub_function diff --git a/imports/construction/helpers/construction_helper.py b/imports/construction/helpers/construction_helper.py index 42709af7..2232643f 100644 --- a/imports/construction/helpers/construction_helper.py +++ b/imports/construction/helpers/construction_helper.py @@ -4,7 +4,7 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2022 Concordia CERC group Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca """ -import sys + from helpers import constants as cte @@ -13,31 +13,6 @@ class ConstructionHelper: Construction helper """ # NREL - _function_to_nrel = { - cte.RESIDENTIAL: 'residential', - cte.SINGLE_FAMILY_HOUSE: 'residential', - cte.MULTI_FAMILY_HOUSE: 'residential', - cte.ROW_HOSE: 'residential', - cte.MID_RISE_APARTMENT: 'midrise apartment', - cte.HIGH_RISE_APARTMENT: 'high-rise apartment', - cte.SMALL_OFFICE: 'small office', - cte.MEDIUM_OFFICE: 'medium office', - cte.LARGE_OFFICE: 'large office', - cte.EDUCATION: 'primary school', - cte.PRIMARY_SCHOOL: 'primary school', - cte.SECONDARY_SCHOOL: 'secondary school', - cte.STAND_ALONE_RETAIL: 'stand-alone retail', - cte.HOSPITAL: 'hospital', - cte.OUT_PATIENT_HEALTH_CARE: 'outpatient healthcare', - cte.STRIP_MALL: 'strip mall', - cte.SUPERMARKET: 'supermarket', - cte.WAREHOUSE: 'warehouse', - cte.QUICK_SERVICE_RESTAURANT: 'quick service restaurant', - cte.FULL_SERVICE_RESTAURANT: 'full service restaurant', - cte.SMALL_HOTEL: 'small hotel', - cte.LARGE_HOTEL: 'large hotel' - } - _nrel_standards = { 'ASHRAE Std189': 1, 'ASHRAE 90.1_2004': 2 @@ -72,18 +47,6 @@ class ConstructionHelper: cte.ROOF: 'roof' } - @staticmethod - def nrel_from_libs_function(function): - """ - Get NREL function from the given internal function key - :param function: str - :return: str - """ - try: - return ConstructionHelper._function_to_nrel[function] - except KeyError: - sys.stderr.write('Error: keyword not found.\n') - @staticmethod def yoc_to_nrel_standard(year_of_construction): """ @@ -118,4 +81,4 @@ class ConstructionHelper: :return: str """ reference_city = ConstructionHelper.city_to_reference_city(city) - return ConstructionHelper._reference_city_to_nrel_climate_zone[reference_city] \ No newline at end of file + return ConstructionHelper._reference_city_to_nrel_climate_zone[reference_city] diff --git a/imports/construction/nrcan_physics_parameters.py b/imports/construction/nrcan_physics_parameters.py index 258673db..5a442929 100644 --- a/imports/construction/nrcan_physics_parameters.py +++ b/imports/construction/nrcan_physics_parameters.py @@ -9,6 +9,7 @@ import sys from catalog_factories.construction_catalog_factory import ConstructionCatalogFactory from city_model_structure.building_demand.layer import Layer from city_model_structure.building_demand.material import Material +from helpers.dictionaries import Dictionaries from imports.construction.helpers.construction_helper import ConstructionHelper from imports.construction.helpers.storeys_generation import StoreysGeneration @@ -31,7 +32,7 @@ class NrcanPhysicsParameters: canel_catalog = ConstructionCatalogFactory('nrcan').catalog for building in city.buildings: try: - function = ConstructionHelper().nrel_from_libs_function(building.function) + function = Dictionaries().hub_function_to_nrcan_construction_function[building.function] archetype = self._search_archetype(canel_catalog, function, building.year_of_construction, self._climate_zone) except KeyError: diff --git a/imports/construction/nrel_physics_parameters.py b/imports/construction/nrel_physics_parameters.py index 2ed1c097..ba3fb31c 100644 --- a/imports/construction/nrel_physics_parameters.py +++ b/imports/construction/nrel_physics_parameters.py @@ -10,6 +10,7 @@ import sys from catalog_factories.construction_catalog_factory import ConstructionCatalogFactory from city_model_structure.building_demand.layer import Layer from city_model_structure.building_demand.material import Material +from helpers.dictionaries import Dictionaries from imports.construction.helpers.construction_helper import ConstructionHelper from imports.construction.helpers.storeys_generation import StoreysGeneration @@ -22,6 +23,7 @@ class NrelPhysicsParameters: self._city = city self._path = base_path self._divide_in_storeys = divide_in_storeys + print(city.name) self._climate_zone = ConstructionHelper.city_to_nrel_climate_zone(city.name) def enrich_buildings(self): @@ -32,7 +34,7 @@ class NrelPhysicsParameters: nrel_catalog = ConstructionCatalogFactory('nrel').catalog for building in city.buildings: try: - function = ConstructionHelper().nrel_from_libs_function(building.function) + function = Dictionaries().hub_function_to_nrel_construction_function[building.function] archetype = self._search_archetype(nrel_catalog, function, building.year_of_construction, self._climate_zone) except KeyError: diff --git a/imports/geometry/citygml.py b/imports/geometry/citygml.py index 758882e2..e0da92bf 100644 --- a/imports/geometry/citygml.py +++ b/imports/geometry/citygml.py @@ -4,15 +4,12 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2022 Concordia CERC group Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca """ -import math -import sys import numpy as np import xmltodict from city_model_structure.city import City from city_model_structure.building import Building from city_model_structure.parts_consisting_building import PartsConsistingBuilding -from helpers.geometry_helper import GeometryHelper from imports.geometry.citygml_classes.citygml_lod2 import CityGmlLod2 from imports.geometry.citygml_classes.citygml_lod1 import CityGmlLod1 @@ -56,7 +53,6 @@ class CityGml: }, force_list=force_list) self._city_objects = None - self._geometry = GeometryHelper() if 'boundedBy' in self._gml['CityModel']: for bound in self._gml['CityModel']['boundedBy']: envelope = bound['Envelope'] diff --git a/imports/geometry/citygml_classes/citygml_base.py b/imports/geometry/citygml_classes/citygml_base.py index c4b1182f..01406509 100644 --- a/imports/geometry/citygml_classes/citygml_base.py +++ b/imports/geometry/citygml_classes/citygml_base.py @@ -6,8 +6,6 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca """ from abc import ABC -import numpy as np -from imports.geometry.helpers.geometry_helper import GeometryHelper class CityGmlBase(ABC): diff --git a/imports/geometry/helpers/geometry_helper.py b/imports/geometry/helpers/geometry_helper.py index 389ff6ac..b9384801 100644 --- a/imports/geometry/helpers/geometry_helper.py +++ b/imports/geometry/helpers/geometry_helper.py @@ -5,7 +5,6 @@ Copyright © 2022 Concordia CERC group Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca """ -import helpers.constants as cte import numpy as np @@ -13,280 +12,6 @@ class GeometryHelper: """ Geometry helper """ - # function - _pluto_to_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_to_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 - } - # function - _alkis_to_function = { - - } - - # usage - _function_to_usage = { - cte.RESIDENTIAL: cte.RESIDENTIAL, - cte.SINGLE_FAMILY_HOUSE: cte.SINGLE_FAMILY_HOUSE, - cte.MULTI_FAMILY_HOUSE: cte.MULTI_FAMILY_HOUSE, - cte.ROW_HOSE: cte.RESIDENTIAL, - cte.MID_RISE_APARTMENT: cte.RESIDENTIAL, - cte.HIGH_RISE_APARTMENT: cte.RESIDENTIAL, - cte.SMALL_OFFICE: cte.OFFICE_AND_ADMINISTRATION, - cte.MEDIUM_OFFICE: cte.OFFICE_AND_ADMINISTRATION, - cte.LARGE_OFFICE: cte.OFFICE_AND_ADMINISTRATION, - cte.PRIMARY_SCHOOL: cte.EDUCATION, - cte.SECONDARY_SCHOOL: cte.EDUCATION, - cte.STAND_ALONE_RETAIL: cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, - cte.HOSPITAL: cte.HEALTH_CARE, - cte.OUT_PATIENT_HEALTH_CARE: cte.HEALTH_CARE, - cte.STRIP_MALL: cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, - cte.SUPERMARKET: cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD, - cte.WAREHOUSE: cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, - cte.QUICK_SERVICE_RESTAURANT: cte.RESTAURANT, - cte.FULL_SERVICE_RESTAURANT: cte.RESTAURANT, - cte.SMALL_HOTEL: cte.HOTEL, - cte.LARGE_HOTEL: cte.HOTEL, - cte.INDUSTRY:cte.INDUSTRY - } - - @staticmethod - def libs_function_from_hft(building_hft_function): - """ - Get internal function from the given HfT function - :param building_hft_function: str - :return: str - """ - return GeometryHelper._hft_to_function[building_hft_function] - - @staticmethod - def libs_function_from_pluto(building_pluto_function): - """ - Get internal function from the given pluto function - :param building_pluto_function: str - :return: str - """ - return GeometryHelper._pluto_to_function[building_pluto_function] - - @staticmethod - def libs_usage_from_libs_function(building_function): - """ - Get the internal usage for the given internal building function - :param building_function: str - :return: str - """ - return GeometryHelper._function_to_usage[building_function] - @staticmethod def to_points_matrix(points): """ diff --git a/imports/usage/comnet_usage_parameters.py b/imports/usage/comnet_usage_parameters.py index b5bfb8cc..82d5ef16 100644 --- a/imports/usage/comnet_usage_parameters.py +++ b/imports/usage/comnet_usage_parameters.py @@ -9,7 +9,7 @@ import sys import numpy import helpers.constants as cte -from imports.usage.helpers.usage_helper import UsageHelper +from helpers.dictionaries import Dictionaries from city_model_structure.building_demand.usage import Usage from city_model_structure.building_demand.lighting import Lighting from city_model_structure.building_demand.occupancy import Occupancy @@ -36,7 +36,7 @@ class ComnetUsageParameters: city = self._city comnet_catalog = UsageCatalogFactory('comnet').catalog for building in city.buildings: - usage_name = UsageHelper.comnet_from_hub_usage(building.function) + usage_name = Dictionaries().hub_usage_to_comnet_usage[building.function] try: archetype_usage = self._search_archetypes(comnet_catalog, usage_name) except KeyError: diff --git a/imports/usage/helpers/schedules_helper.py b/imports/usage/helpers/schedules_helper.py deleted file mode 100644 index 66510083..00000000 --- a/imports/usage/helpers/schedules_helper.py +++ /dev/null @@ -1,87 +0,0 @@ -""" -Schedules helper -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 -""" -import sys -import helpers.constants as cte - - -class SchedulesHelper: - """ - Schedules helper - """ - _usage_to_comnet = { - cte.RESIDENTIAL: 'C-12 Residential', - cte.INDUSTRY: 'C-10 Warehouse', - cte.OFFICE_AND_ADMINISTRATION: 'C-5 Office', - cte.HOTEL: 'C-3 Hotel', - cte.HEALTH_CARE: 'C-2 Health', - cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'C-8 Retail', - cte.HALL: 'C-8 Retail', - cte.RESTAURANT: 'C-7 Restaurant', - cte.EDUCATION: 'C-9 School' - } - - _comnet_to_data_type = { - 'Fraction': cte.FRACTION, - 'OnOff': cte.ON_OFF, - 'Temperature': cte.ANY_NUMBER - } - - # usage - _function_to_usage = { - 'full service restaurant': cte.RESTAURANT, - 'high-rise apartment': cte.RESIDENTIAL, - 'hospital': cte.HEALTH_CARE, - 'large hotel': cte.HOTEL, - 'large office': cte.OFFICE_AND_ADMINISTRATION, - 'medium office': cte.OFFICE_AND_ADMINISTRATION, - 'midrise apartment': cte.RESIDENTIAL, - 'outpatient healthcare': cte.HEALTH_CARE, - 'primary school': cte.EDUCATION, - 'quick service restaurant': cte.RESTAURANT, - 'secondary school': cte.EDUCATION, - 'small hotel': cte.HOTEL, - 'small office': cte.OFFICE_AND_ADMINISTRATION, - 'stand-alone-retail': cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, - 'strip mall': cte.HALL, - 'supermarket': cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD, - 'warehouse': cte.INDUSTRY, - 'residential': cte.RESIDENTIAL - } - - @staticmethod - def comnet_from_usage(usage): - """ - Get Comnet usage from the given internal usage key - :param usage: str - :return: str - """ - try: - return SchedulesHelper._usage_to_comnet[usage] - except KeyError: - sys.stderr.write('Error: keyword not found.\n') - - @staticmethod - def data_type_from_comnet(comnet_data_type): - """ - Get data_type from the Comnet data type definitions - :param comnet_data_type: str - :return: str - """ - try: - return SchedulesHelper._comnet_to_data_type[comnet_data_type] - except KeyError: - raise ValueError(f"Error: comnet data type keyword not found.") - - @staticmethod - def usage_from_function(building_function): - """ - Get the internal usage for the given internal building function - :param building_function: str - :return: str - """ - return SchedulesHelper._function_to_usage[building_function] diff --git a/imports/usage/helpers/usage_helper.py b/imports/usage/helpers/usage_helper.py deleted file mode 100644 index eece9580..00000000 --- a/imports/usage/helpers/usage_helper.py +++ /dev/null @@ -1,169 +0,0 @@ -""" -Usage helper -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Concordia CERC group -Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca -""" -import sys -import helpers.constants as cte - - -class UsageHelper: - """ - Usage helper class - """ - _usage_to_hft = { - cte.RESIDENTIAL: 'residential', - cte.SINGLE_FAMILY_HOUSE: 'Single family house', - cte.MULTI_FAMILY_HOUSE: 'Multi-family house', - cte.EDUCATION: 'education', - cte.SCHOOL_WITHOUT_SHOWER: 'school without shower', - cte.SCHOOL_WITH_SHOWER: 'school with shower', - cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'retail', - cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'retail shop / refrigerated food', - cte.HOTEL: 'hotel', - cte.HOTEL_MEDIUM_CLASS: 'hotel (Medium-class)', - cte.DORMITORY: 'dormitory', - cte.INDUSTRY: 'industry', - cte.RESTAURANT: 'restaurant', - cte.HEALTH_CARE: 'health care', - cte.RETIREMENT_HOME_OR_ORPHANAGE: 'Home for the aged or orphanage', - cte.OFFICE_AND_ADMINISTRATION: 'office and administration', - cte.EVENT_LOCATION: 'event location', - cte.HALL: 'hall', - cte.SPORTS_LOCATION: 'sport location', - cte.LABOR: 'Labor', - cte.GREEN_HOUSE: 'green house', - cte.NON_HEATED: 'non-heated'} - - @staticmethod - def hft_from_libs_usage(usage): - """ - Get HfT usage from the given internal usage key - :param usage: str - :return: str - """ - try: - return UsageHelper._usage_to_hft[usage] - except KeyError: - sys.stderr.write('Error: keyword not found to translate from libs_usage to hft usage.\n') - - _usage_to_comnet = { - cte.RESIDENTIAL: 'BA Multifamily', - cte.SINGLE_FAMILY_HOUSE: 'BA Multifamily', - cte.MULTI_FAMILY_HOUSE: 'BA Multifamily', - cte.EDUCATION: 'BA School/University', - cte.SCHOOL_WITHOUT_SHOWER: 'BA School/University', - cte.SCHOOL_WITH_SHOWER: 'BA School/University', - cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'BA Retail', - cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'BA Retail', - cte.HOTEL: 'BA Hotel', - cte.HOTEL_MEDIUM_CLASS: 'BA Hotel', - cte.DORMITORY: 'BA Dormitory', - cte.INDUSTRY: 'BA Manufacturing Facility', - cte.RESTAURANT: 'BA Dining: Family', - cte.HEALTH_CARE: 'BA Hospital', - cte.RETIREMENT_HOME_OR_ORPHANAGE: 'BA Multifamily', - cte.OFFICE_AND_ADMINISTRATION: 'BA Office', - cte.EVENT_LOCATION: 'BA Convention Center', - cte.HALL: 'BA Convention Center', - cte.SPORTS_LOCATION: 'BA Sports Arena', - cte.LABOR: 'BA Gymnasium', - cte.GREEN_HOUSE: cte.GREEN_HOUSE, - cte.NON_HEATED: cte.NON_HEATED - } - - _comnet_schedules_key_to_comnet_schedules = { - 'C-1 Assembly': 'C-1 Assembly', - 'C-2 Public': 'C-2 Health', - 'C-3 Hotel Motel': 'C-3 Hotel', - 'C-4 Manufacturing': 'C-4 Manufacturing', - 'C-5 Office': 'C-5 Office', - 'C-6 Parking Garage': 'C-6 Parking', - 'C-7 Restaurant': 'C-7 Restaurant', - 'C-8 Retail': 'C-8 Retail', - 'C-9 Schools': 'C-9 School', - 'C-10 Warehouse': 'C-10 Warehouse', - 'C-11 Laboratory': 'C-11 Lab', - 'C-12 Residential': 'C-12 Residential', - 'C-13 Data Center': 'C-13 Data', - 'C-14 Gymnasium': 'C-14 Gymnasium'} - - _comnet_schedules_key_to_usage = { - 'C-1 Assembly': 'C-1 Assembly', - 'C-2 Public': 'C-2 Health', - 'C-3 Hotel Motel': 'C-3 Hotel', - 'C-4 Manufacturing': 'C-4 Manufacturing', - 'C-5 Office': 'C-5 Office', - 'C-6 Parking Garage': 'C-6 Parking', - 'C-7 Restaurant': 'C-7 Restaurant', - 'C-8 Retail': 'C-8 Retail', - 'C-9 Schools': 'C-9 School', - 'C-10 Warehouse': 'C-10 Warehouse', - 'C-11 Laboratory': 'C-11 Lab', - 'C-12 Residential': 'C-12 Residential', - 'C-13 Data Center': 'C-13 Data', - 'C-14 Gymnasium': 'C-14 Gymnasium'} - - @staticmethod - def comnet_from_hub_usage(usage): - """ - Get Comnet usage from the given internal usage key - :param usage: str - :return: str - """ - try: - return UsageHelper._usage_to_comnet[usage] - except KeyError: - sys.stderr.write('Error: keyword not found to translate from hub_usage to comnet usage.\n') - - @staticmethod - def schedules_key(usage): - """ - Get Comnet schedules key from the list found in the Comnet usage file - :param usage: str - :return: str - """ - try: - return UsageHelper._comnet_schedules_key_to_comnet_schedules[usage] - except KeyError: - sys.stderr.write('Error: Comnet keyword not found. An update of the Comnet files might have been ' - 'done changing the keywords.\n') - - _usage_to_nrcan = { - cte.RESIDENTIAL: 'Multi-unit residential building', - cte.SINGLE_FAMILY_HOUSE: 'Multi-unit residential building', - cte.MULTI_FAMILY_HOUSE: 'Multi-unit residential building', - cte.EDUCATION: 'School/university', - cte.SCHOOL_WITHOUT_SHOWER: 'School/university', - cte.SCHOOL_WITH_SHOWER: 'School/university', - cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'Retail', - cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'Retail', - cte.HOTEL: 'Hotel', - cte.HOTEL_MEDIUM_CLASS: 'Hotel', - cte.DORMITORY: 'Dormitory', - cte.INDUSTRY: 'Manufacturing Facility', - cte.RESTAURANT: 'Dining - family', - cte.HEALTH_CARE: 'Hospital', - cte.RETIREMENT_HOME_OR_ORPHANAGE: 'Multi-unit residential building', - cte.OFFICE_AND_ADMINISTRATION: 'Office', - cte.EVENT_LOCATION: 'Convention centre', - cte.HALL: 'Convention centre', - cte.SPORTS_LOCATION: 'Gymnasium', - cte.LABOR: 'Gymnasium', - cte.GREEN_HOUSE: cte.GREEN_HOUSE, - cte.NON_HEATED: cte.NON_HEATED - } - - @staticmethod - def nrcan_from_hub_usage(usage): - """ - Get Nrcan usage from the given internal usage key - :param usage: str - :return: str - """ - try: - return UsageHelper._usage_to_nrcan[usage] - except KeyError: - sys.stderr.write('Error: keyword not found to translate from hub_usage to nrcan usage.\n') - diff --git a/imports/usage/nrcan_usage_parameters.py b/imports/usage/nrcan_usage_parameters.py index 92acfb65..4d16c8dc 100644 --- a/imports/usage/nrcan_usage_parameters.py +++ b/imports/usage/nrcan_usage_parameters.py @@ -8,7 +8,7 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca import sys import helpers.constants as cte -from imports.usage.helpers.usage_helper import UsageHelper +from helpers.dictionaries import Dictionaries from city_model_structure.building_demand.usage import Usage from city_model_structure.building_demand.lighting import Lighting from city_model_structure.building_demand.occupancy import Occupancy @@ -35,7 +35,7 @@ class NrcanUsageParameters: comnet_catalog = UsageCatalogFactory('comnet').catalog for building in city.buildings: - usage_name = UsageHelper.nrcan_from_hub_usage(building.function) + usage_name = Dictionaries().hub_usage_to_nrcan_usage[building.function] try: archetype_usage = self._search_archetypes(nrcan_catalog, usage_name) except KeyError: @@ -43,7 +43,7 @@ class NrcanUsageParameters: f' {building.function}') return - usage_name = UsageHelper.comnet_from_hub_usage(building.function) + usage_name = Dictionaries().hub_usage_to_comnet_usage[building.function] try: comnet_archetype_usage = self._search_archetypes(comnet_catalog, usage_name) except KeyError: diff --git a/unittests/test_construction_factory.py b/unittests/test_construction_factory.py index 5be1db00..5698c216 100644 --- a/unittests/test_construction_factory.py +++ b/unittests/test_construction_factory.py @@ -9,7 +9,7 @@ from unittest import TestCase from imports.geometry_factory import GeometryFactory from imports.construction_factory import ConstructionFactory -from imports.geometry.helpers.geometry_helper import GeometryHelper +from helpers.dictionaries import Dictionaries class TestConstructionFactory(TestCase): @@ -34,9 +34,9 @@ class TestConstructionFactory(TestCase): @staticmethod def _internal_function(function_format, original_function): if function_format == 'hft': - new_function = GeometryHelper.libs_function_from_hft(original_function) + new_function = Dictionaries().hft_function_to_hub_function[original_function] elif function_format == 'pluto': - new_function = GeometryHelper.libs_function_from_pluto(original_function) + new_function = Dictionaries().pluto_function_to_hub_function[original_function] else: raise Exception('Function key not recognized. Implemented only "hft" and "pluto"') return new_function @@ -51,7 +51,7 @@ class TestConstructionFactory(TestCase): city = self._get_citygml(file) for building in city.buildings: building.function = self._internal_function(function_format, building.function) - self.assertEqual(building.function, 'residential', 'format hft') + self.assertEqual('residential', building.function, 'format hft') # case 2: Pluto file = 'pluto_building.gml' @@ -59,7 +59,7 @@ class TestConstructionFactory(TestCase): city = self._get_citygml(file) for building in city.buildings: building.function = self._internal_function(function_format, building.function) - self.assertEqual(building.function, 'secondary school', 'format pluto') + self.assertEqual('education', building.function, 'format pluto') # case 3: Alkis file = 'one_building_in_kelowna_alkis.gml' @@ -180,7 +180,7 @@ class TestConstructionFactory(TestCase): city = self._get_citygml(file) for building in city.buildings: building.year_of_construction = 2005 - building.function = GeometryHelper.libs_function_from_pluto(building.function) + building.function = self._internal_function('pluto', building.function) ConstructionFactory('nrel', city).enrich() self._check_buildings(city) diff --git a/unittests/test_enrichement.py b/unittests/test_enrichement.py index e9d3b9ca..8ffafd3c 100644 --- a/unittests/test_enrichement.py +++ b/unittests/test_enrichement.py @@ -7,7 +7,7 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca from pathlib import Path from unittest import TestCase from imports.geometry_factory import GeometryFactory -from imports.geometry.helpers.geometry_helper import GeometryHelper +from helpers.dictionaries import Dictionaries from imports.usage_factory import UsageFactory from imports.construction_factory import ConstructionFactory @@ -71,10 +71,10 @@ class TestGeometryFactory(TestCase): def _prepare_case_usage_first(city, input_key, construction_key, usage_key): if input_key == 'pluto': for building in city.buildings: - building.function = GeometryHelper.libs_function_from_pluto(building.function) + building.function = Dictionaries().pluto_function_to_hub_function[building.function] elif input_key == 'hft': for building in city.buildings: - building.function = GeometryHelper.libs_function_from_hft(building.function) + building.function = Dictionaries().hft_function_to_hub_function[building.function] UsageFactory(usage_key, city).enrich() ConstructionFactory(construction_key, city).enrich() @@ -82,16 +82,16 @@ class TestGeometryFactory(TestCase): def _prepare_case_construction_first(city, input_key, construction_key, usage_key): if input_key == 'pluto': for building in city.buildings: - building.function = GeometryHelper.libs_function_from_pluto(building.function) + building.function = Dictionaries().pluto_function_to_hub_function[building.function] elif input_key == 'hft': for building in city.buildings: - building.function = GeometryHelper.libs_function_from_hft(building.function) + building.function = Dictionaries().hft_function_to_hub_function[building.function] print(construction_key, usage_key) ConstructionFactory(construction_key, city).enrich() UsageFactory(usage_key, city).enrich() def _test_hft(self, file): - _construction_keys = ['nrcan', 'nrel'] + _construction_keys = ['nrel'] _usage_keys = ['comnet', 'nrcan'] for construction_key in _construction_keys: for usage_key in _usage_keys: diff --git a/unittests/test_exports.py b/unittests/test_exports.py index db564af2..c2961274 100644 --- a/unittests/test_exports.py +++ b/unittests/test_exports.py @@ -10,7 +10,7 @@ from pathlib import Path from unittest import TestCase import pandas as pd from imports.geometry_factory import GeometryFactory -from imports.geometry.helpers.geometry_helper import GeometryHelper +from helpers.dictionaries import Dictionaries from imports.construction_factory import ConstructionFactory from imports.usage_factory import UsageFactory from exports.exports_factory import ExportsFactory @@ -48,7 +48,7 @@ class TestExports(TestCase): file_path = (self._example_path / 'one_building_in_kelowna.gml').resolve() self._complete_city = self._get_citygml(file_path) for building in self._complete_city.buildings: - building.function = GeometryHelper().libs_function_from_hft(building.function) + building.function = Dictionaries().hft_function_to_hub_function[building.function] building.year_of_construction = 2006 ConstructionFactory('nrel', self._complete_city).enrich() UsageFactory('ca', self._complete_city).enrich() diff --git a/unittests/test_usage_catalog.py b/unittests/test_usage_catalog.py index 2cc5dfe5..c604efe7 100644 --- a/unittests/test_usage_catalog.py +++ b/unittests/test_usage_catalog.py @@ -20,4 +20,4 @@ class TestConstructionCatalog(TestCase): catalog = UsageCatalogFactory('nrcan').catalog self.assertIsNotNone(catalog, 'catalog is none') content = catalog.entries() - self.assertEqual(274, len(content.usages), 'Wrong number of usages') + self.assertEqual(34, len(content.usages), 'Wrong number of usages') diff --git a/unittests/test_usage_factory.py b/unittests/test_usage_factory.py index 39cbe500..cc8c748d 100644 --- a/unittests/test_usage_factory.py +++ b/unittests/test_usage_factory.py @@ -9,7 +9,7 @@ from unittest import TestCase from imports.geometry_factory import GeometryFactory from imports.usage_factory import UsageFactory -from imports.geometry.helpers.geometry_helper import GeometryHelper +from helpers.dictionaries import Dictionaries class TestUsageFactory(TestCase): @@ -85,7 +85,7 @@ class TestUsageFactory(TestCase): file = 'pluto_building.gml' city = self._get_citygml(file) for building in city.buildings: - building.function = GeometryHelper.libs_function_from_pluto(building.function) + building.function = Dictionaries().pluto_function_to_hub_function[building.function] UsageFactory('comnet', city).enrich() self._check_buildings(city) From 0605d5b4f6fc1bd9cd1a5cc0562a5060037d6fc4 Mon Sep 17 00:00:00 2001 From: Pilar Date: Tue, 10 Jan 2023 09:55:38 -0500 Subject: [PATCH 7/8] updating the code to changes in hub (not finished -> not working) --- imports/usage_factory.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/imports/usage_factory.py b/imports/usage_factory.py index ed567b89..2d834a4d 100644 --- a/imports/usage_factory.py +++ b/imports/usage_factory.py @@ -26,14 +26,15 @@ class UsageFactory: """ Enrich the city with COMNET usage library """ - self._city.level_of_detail.usage_name = 2 + self._city.level_of_detail.usage = 2 ComnetUsageParameters(self._city, self._base_path).enrich_buildings() def _nrcan(self): """ Enrich the city with NRCAN usage library """ - return NrcanUsageParameters(self._city, self._base_path).enrich_buildings() + self._city.level_of_detail.usage = 2 + NrcanUsageParameters(self._city, self._base_path).enrich_buildings() def enrich(self): """ From 64fd59db73f49cd6a5da889c34c4ed8281842dfb Mon Sep 17 00:00:00 2001 From: Pilar Date: Tue, 10 Jan 2023 10:45:05 -0500 Subject: [PATCH 8/8] changed parameter name 'sra' to 'simplified_radiosity_algorithm' in simplified_radiosity_algorithm exporter --- exports/formats/simplified_radiosity_algorithm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exports/formats/simplified_radiosity_algorithm.py b/exports/formats/simplified_radiosity_algorithm.py index d40a4908..84e6bd30 100644 --- a/exports/formats/simplified_radiosity_algorithm.py +++ b/exports/formats/simplified_radiosity_algorithm.py @@ -48,7 +48,7 @@ class SimplifiedRadiosityAlgorithm: for surface in building.surfaces: surface_dict = { '@id': f'{surface.id}', - '@ShortWaveReflectance': f'{surface.swr}' + '@ShortWaveReflectance': f'{surface.short_wave_reflectance}' } for point_index, point in enumerate(surface.perimeter_polygon.coordinates): point = self._correct_point(point)