From 183807b8e0569db82bed07c464490df1976461d2 Mon Sep 17 00:00:00 2001 From: p_monsalvete Date: Mon, 29 May 2023 11:56:56 -0400 Subject: [PATCH] adapted systems importer to new catalog --- .../data_models/energy_systems/archetype.py | 10 +- .../data_models/energy_systems/content.py | 36 +++- .../energy_systems/distribution_system.py | 36 +++- .../energy_systems/emission_system.py | 37 +++- .../energy_systems/generation_system.py | 38 +++- .../{equipment.py => system.py} | 8 +- .../energy_systems/montreal_custom_catalog.py | 184 ++++++++++++++---- hub/city_model_structure/building.py | 21 +- .../building_demand/surface.py | 7 +- .../montreal_custom_systems.xml | 27 +-- .../insel/insel_monthly_energy_balance.py | 5 +- hub/helpers/constants.py | 2 + ..._system_to_hub_energy_generation_system.py | 24 ++- ...ontreal_custom_energy_system_parameters.py | 2 +- .../results/simplified_radiosity_algorithm.py | 13 +- hub/unittests/test_systems_catalog.py | 13 +- hub/unittests/test_systems_factory.py | 3 +- 17 files changed, 357 insertions(+), 109 deletions(-) rename hub/catalog_factories/data_models/energy_systems/{equipment.py => system.py} (94%) diff --git a/hub/catalog_factories/data_models/energy_systems/archetype.py b/hub/catalog_factories/data_models/energy_systems/archetype.py index b770eae1..632fc999 100644 --- a/hub/catalog_factories/data_models/energy_systems/archetype.py +++ b/hub/catalog_factories/data_models/energy_systems/archetype.py @@ -7,15 +7,15 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca from typing import List -from hub.catalog_factories.data_models.energy_systems.equipment import Equipment +from hub.catalog_factories.data_models.energy_systems.system import System class Archetype: - def __init__(self, lod, name, equipments): + def __init__(self, lod, name, systems): self._lod = lod self._name = name - self._equipments = equipments + self._systems = systems @property def lod(self): @@ -34,9 +34,9 @@ class Archetype: return f'{self._name}_lod{self._lod}' @property - def equipments(self) -> List[Equipment]: + def systems(self) -> List[System]: """ Get list of equipments that compose the total energy system :return: [Equipment] """ - return self._equipments + return self._systems diff --git a/hub/catalog_factories/data_models/energy_systems/content.py b/hub/catalog_factories/data_models/energy_systems/content.py index 53c07efb..7611e1e7 100644 --- a/hub/catalog_factories/data_models/energy_systems/content.py +++ b/hub/catalog_factories/data_models/energy_systems/content.py @@ -7,20 +7,44 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca class Content: - def __init__(self, archetypes, equipments): + def __init__(self, archetypes, systems, generations, distributions, emissions): self._archetypes = archetypes - self._equipments = equipments + self._systems = systems + self._generations = generations + self._distributions = distributions + self._emissions = emissions @property def archetypes(self): """ - All archetype systems in the catalog + All archetype system clusters in the catalog """ return self._archetypes @property - def equipments(self): + def systems(self): """ - All equipments in the catalog + All systems in the catalog """ - return self._equipments + return self._systems + + @property + def generation_equipments(self): + """ + All generation equipments in the catalog + """ + return self._generations + + @property + def distribution_equipments(self): + """ + All distribution equipments in the catalog + """ + return self._distributions + + @property + def emission_equipments(self): + """ + All emission equipments in the catalog + """ + return self._emissions diff --git a/hub/catalog_factories/data_models/energy_systems/distribution_system.py b/hub/catalog_factories/data_models/energy_systems/distribution_system.py index d189ea03..77176eb4 100644 --- a/hub/catalog_factories/data_models/energy_systems/distribution_system.py +++ b/hub/catalog_factories/data_models/energy_systems/distribution_system.py @@ -7,15 +7,49 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca class DistributionSystem: - def __init__(self, system_type, supply_temperature, distribution_consumption_fix_flow, + def __init__(self, system_id, name, system_type, supply_temperature, distribution_consumption_fix_flow, distribution_consumption_variable_flow, heat_losses): + self._system_id = system_id + self._name = name self._type = system_type self._supply_temperature = supply_temperature self._distribution_consumption_fix_flow = distribution_consumption_fix_flow self._distribution_consumption_variable_flow = distribution_consumption_variable_flow self._heat_losses = heat_losses + @property + def id(self): + """ + Get system id + :return: float + """ + return self._system_id + + @id.setter + def id(self, value): + """ + Set system id + :param value: float + """ + self._system_id = value + + @property + def name(self): + """ + Get name + :return: string + """ + return self._name + + @name.setter + def name(self, value): + """ + Set name + :param value: string + """ + self._name = value + @property def type(self): """ diff --git a/hub/catalog_factories/data_models/energy_systems/emission_system.py b/hub/catalog_factories/data_models/energy_systems/emission_system.py index d9b0f4e5..61f917fc 100644 --- a/hub/catalog_factories/data_models/energy_systems/emission_system.py +++ b/hub/catalog_factories/data_models/energy_systems/emission_system.py @@ -7,10 +7,45 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca class EmissionSystem: - def __init__(self, system_type, parasitic_energy_consumption): + def __init__(self, system_id, name, system_type, parasitic_energy_consumption): + + self._system_id = system_id + self._name = name self._type = system_type self._parasitic_energy_consumption = parasitic_energy_consumption + @property + def id(self): + """ + Get system id + :return: float + """ + return self._system_id + + @id.setter + def id(self, value): + """ + Set system id + :param value: float + """ + self._system_id = value + + @property + def name(self): + """ + Get name + :return: string + """ + return self._name + + @name.setter + def name(self, value): + """ + Set name + :param value: string + """ + self._name = value + @property def type(self): """ diff --git a/hub/catalog_factories/data_models/energy_systems/generation_system.py b/hub/catalog_factories/data_models/energy_systems/generation_system.py index 51a5325c..79665f76 100644 --- a/hub/catalog_factories/data_models/energy_systems/generation_system.py +++ b/hub/catalog_factories/data_models/energy_systems/generation_system.py @@ -10,9 +10,11 @@ from typing import Union class GenerationSystem: - def __init__(self, system_type, fuel_type, source_types, heat_efficiency, cooling_efficiency, electricity_efficiency, - source_temperature, source_mass_flow, storage, auxiliary_equipment): + def __init__(self, system_id, name, system_type, fuel_type, source_types, heat_efficiency, cooling_efficiency, + electricity_efficiency, source_temperature, source_mass_flow, storage, auxiliary_equipment): + self._system_id = system_id + self._name = name self._type = system_type self._fuel_type = fuel_type self._source_types = source_types @@ -24,6 +26,38 @@ class GenerationSystem: self._storage = storage self._auxiliary_equipment = auxiliary_equipment + @property + def id(self): + """ + Get system id + :return: float + """ + return self._system_id + + @id.setter + def id(self, value): + """ + Set system id + :param value: float + """ + self._system_id = value + + @property + def name(self): + """ + Get name + :return: string + """ + return self._name + + @name.setter + def name(self, value): + """ + Set name + :param value: string + """ + self._name = value + @property def type(self): """ diff --git a/hub/catalog_factories/data_models/energy_systems/equipment.py b/hub/catalog_factories/data_models/energy_systems/system.py similarity index 94% rename from hub/catalog_factories/data_models/energy_systems/equipment.py rename to hub/catalog_factories/data_models/energy_systems/system.py index 9b2ddcd4..f03a9725 100644 --- a/hub/catalog_factories/data_models/energy_systems/equipment.py +++ b/hub/catalog_factories/data_models/energy_systems/system.py @@ -12,10 +12,10 @@ from hub.catalog_factories.data_models.energy_systems.distribution_system import from hub.catalog_factories.data_models.energy_systems.emission_system import EmissionSystem -class Equipment: +class System: def __init__(self, lod, - equipment_id, + system_id, name, demand_types, generation_system, @@ -23,7 +23,7 @@ class Equipment: emission_system): self._lod = lod - self._equipment_id = equipment_id + self._system_id = system_id self._name = name self._demand_types = demand_types self._generation_system = generation_system @@ -44,7 +44,7 @@ class Equipment: Get equipment id :return: string """ - return self._equipment_id + return self._system_id @property def name(self): diff --git a/hub/catalog_factories/energy_systems/montreal_custom_catalog.py b/hub/catalog_factories/energy_systems/montreal_custom_catalog.py index 818c913d..0727e3d0 100644 --- a/hub/catalog_factories/energy_systems/montreal_custom_catalog.py +++ b/hub/catalog_factories/energy_systems/montreal_custom_catalog.py @@ -8,10 +8,11 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca import xmltodict from hub.catalog_factories.catalog import Catalog -from hub.catalog_factories.data_models.energy_systems.equipment import Equipment +from hub.catalog_factories.data_models.energy_systems.system import System from hub.catalog_factories.data_models.energy_systems.content import Content from hub.catalog_factories.data_models.energy_systems.generation_system import GenerationSystem from hub.catalog_factories.data_models.energy_systems.distribution_system import DistributionSystem +from hub.catalog_factories.data_models.energy_systems.emission_system import EmissionSystem from hub.catalog_factories.data_models.energy_systems.archetype import Archetype @@ -19,46 +20,45 @@ class MontrealCustomCatalog(Catalog): def __init__(self, path): path = str(path / 'montreal_custom_systems.xml') with open(path) as xml: - self._archetypes = xmltodict.parse(xml.read(), force_list=('system', 'system_cluster', 'demand', 'system_id')) + self._archetypes = xmltodict.parse(xml.read(), force_list=('system', 'system_cluster', 'equipment', + 'demand', 'system_id')) self._lod = float(self._archetypes['catalog']['@lod']) + self._catalog_generation_equipments = self._load_generation_equipments() + self._catalog_distribution_equipments = self._load_distribution_equipments() + self._catalog_emission_equipments = self._load_emission_equipments() self._catalog_systems = self._load_systems() self._catalog_archetypes = self._load_archetypes() # store the full catalog data model in self._content self._content = Content(self._catalog_archetypes, - self._catalog_systems) + self._catalog_systems, + self._catalog_generation_equipments, + self._catalog_distribution_equipments, + self._catalog_emission_equipments) - def _load_systems(self): - _catalog_systems = [] - systems = self._archetypes['catalog']['systems']['system'] - for system in systems: - system_id = float(system['@id']) - system_type = system['@type'] - fuel_type = system['@fuel_type'] - name = system['name'] - demands = system['demands']['demand'] + def _load_generation_equipments(self): + _equipments = [] + equipments = self._archetypes['catalog']['generation_equipments']['equipment'] + for equipment in equipments: + equipment_id = float(equipment['@id']) + equipment_type = equipment['@type'] + fuel_type = equipment['@fuel_type'] + name = equipment['name'] heating_efficiency = None - if 'heating_efficiency' in system: - heating_efficiency = float(system['heating_efficiency']) + if 'heating_efficiency' in equipment: + heating_efficiency = float(equipment['heating_efficiency']) cooling_efficiency = None - if 'cooling_efficiency' in system: - cooling_efficiency = float(system['cooling_efficiency']) + if 'cooling_efficiency' in equipment: + cooling_efficiency = float(equipment['cooling_efficiency']) electricity_efficiency = None - if 'electricity_efficiency' in system: - electricity_efficiency = float(system['electricity_efficiency']) - distribution_heat_losses = None - if 'distribution_heat_losses' in system: - distribution_heat_losses = float(system['distribution_heat_losses']['#text']) / 100 - distribution_consumption_fix_flow = None - if 'distribution_consumption_fix_flow' in system: - distribution_consumption_fix_flow = float(system['distribution_consumption_fix_flow']['#text']) / 100 - distribution_consumption_variable_flow = None - if 'distribution_consumption_variable_flow' in system: - distribution_consumption_variable_flow = float(system['distribution_consumption_variable_flow']['#text']) / 100 - storage = eval(system['storage'].capitalize()) - generation_system = GenerationSystem(system_type, + if 'electrical_efficiency' in equipment: + electricity_efficiency = float(equipment['electrical_efficiency']) + storage = eval(equipment['storage'].capitalize()) + generation_system = GenerationSystem(equipment_id, + name, + equipment_type, fuel_type, None, heating_efficiency, @@ -68,18 +68,87 @@ class MontrealCustomCatalog(Catalog): None, storage, None) - distribution_system = DistributionSystem(None, + + _equipments.append(generation_system) + return _equipments + + def _load_distribution_equipments(self): + _equipments = [] + equipments = self._archetypes['catalog']['distribution_equipments']['equipment'] + for equipment in equipments: + equipment_id = float(equipment['@id']) + equipment_type = equipment['@type'] + name = equipment['name'] + distribution_heat_losses = None + if 'distribution_heat_losses' in equipment: + distribution_heat_losses = float(equipment['distribution_heat_losses']['#text']) / 100 + distribution_consumption_fix_flow = None + if 'distribution_consumption_fix_flow' in equipment: + distribution_consumption_fix_flow = float(equipment['distribution_consumption_fix_flow']['#text']) / 100 + distribution_consumption_variable_flow = None + if 'distribution_consumption_variable_flow' in equipment: + distribution_consumption_variable_flow = float(equipment['distribution_consumption_variable_flow']['#text']) / 100 + + distribution_system = DistributionSystem(equipment_id, + name, + equipment_type, None, distribution_consumption_fix_flow, distribution_consumption_variable_flow, distribution_heat_losses) - _catalog_systems.append(Equipment(self._lod, - system_id, - name, - demands, - generation_system, - distribution_system, - None)) + + _equipments.append(distribution_system) + return _equipments + + def _load_emission_equipments(self): + _equipments = [] + equipments = self._archetypes['catalog']['dissipation_equipments']['equipment'] + for equipment in equipments: + equipment_id = float(equipment['@id']) + equipment_type = equipment['@type'] + name = equipment['name'] + parasitic_consumption = None + if 'parasitic_consumption' in equipment: + parasitic_consumption = float(equipment['parasitic_consumption']['#text']) / 100 + + emission_system = EmissionSystem(equipment_id, + name, + equipment_type, + parasitic_consumption) + + _equipments.append(emission_system) + return _equipments + + def _load_systems(self): + _catalog_systems = [] + systems = self._archetypes['catalog']['systems']['system'] + for system in systems: + system_id = float(system['@id']) + name = system['name'] + demands = system['demands']['demand'] + generation_equipment = system['equipments']['generation_id'] + _generation_equipment = None + for equipment_archetype in self._catalog_generation_equipments: + if int(equipment_archetype.id) == int(generation_equipment): + _generation_equipment = equipment_archetype + distribution_equipment = system['equipments']['distribution_id'] + _distribution_equipment = None + for equipment_archetype in self._catalog_distribution_equipments: + if int(equipment_archetype.id) == int(distribution_equipment): + _distribution_equipment = equipment_archetype + emission_equipment = system['equipments']['dissipation_id'] + _emission_equipment = None + for equipment_archetype in self._catalog_emission_equipments: + if int(equipment_archetype.id) == int(emission_equipment): + _emission_equipment = equipment_archetype + + _catalog_systems.append(System(self._lod, + system_id, + name, + demands, + _generation_equipment, + _distribution_equipment, + _emission_equipment)) return _catalog_systems def _load_archetypes(self): @@ -102,18 +171,34 @@ class MontrealCustomCatalog(Catalog): :parm: optional category filter """ if category is None: - _names = {'archetypes': [], 'systems': []} + _names = {'archetypes': [], 'systems': [], 'generation_equipments': [], 'distribution_equipments': [], + 'emission_equipments':[]} for archetype in self._content.archetypes: _names['archetypes'].append(archetype.name) - for system in self._content.equipments: + for system in self._content.systems: _names['systems'].append(system.name) + for equipment in self._content.generation_equipments: + _names['generation_equipments'].append(equipment.name) + for equipment in self._content.distribution_equipments: + _names['distribution_equipments'].append(equipment.name) + for equipment in self._content.emission_equipments: + _names['emission_equipments'].append(equipment.name) else: _names = {category: []} if category.lower() == 'archetypes': for archetype in self._content.archetypes: _names[category].append(archetype.name) elif category.lower() == 'systems': - for system in self._content.equipments: + for system in self._content.systems: + _names[category].append(system.name) + elif category.lower() == 'generation_equipments': + for system in self._content.generation_equipments: + _names[category].append(system.name) + elif category.lower() == 'distribution_equipments': + for system in self._content.distribution_equipments: + _names[category].append(system.name) + elif category.lower() == 'emission_equipments': + for system in self._content.emission_equipments: _names[category].append(system.name) else: raise ValueError(f'Unknown category [{category}]') @@ -130,7 +215,13 @@ class MontrealCustomCatalog(Catalog): if category.lower() == 'archetypes': return self._content.archetypes elif category.lower() == 'systems': - return self._content.equipments + return self._content.systems + elif category.lower() == 'generation_equipments': + return self._content.generation_equipments + elif category.lower() == 'distribution_equipments': + return self._content.distribution_equipments + elif category.lower() == 'emission_equipments': + return self._content.emission_equipments else: raise ValueError(f'Unknown category [{category}]') @@ -142,7 +233,16 @@ class MontrealCustomCatalog(Catalog): for entry in self._content.archetypes: if entry.name.lower() == name.lower(): return entry - for entry in self._content.equipments: + for entry in self._content.systems: + if entry.name.lower() == name.lower(): + return entry + for entry in self._content.generation_equipments: + if entry.name.lower() == name.lower(): + return entry + for entry in self._content.distribution_equipments: + if entry.name.lower() == name.lower(): + return entry + for entry in self._content.emission_equipments: if entry.name.lower() == name.lower(): return entry raise IndexError(f"{name} doesn't exists in the catalog") diff --git a/hub/city_model_structure/building.py b/hub/city_model_structure/building.py index 4c92b4ec..7262e46e 100644 --- a/hub/city_model_structure/building.py +++ b/hub/city_model_structure/building.py @@ -671,15 +671,28 @@ class Building(CityObject): Get total electricity produced onsite in Wh return: dict """ + # Add other systems whenever new ones appear + orientation_losses_factor = {cte.MONTH: {'north': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + 'east': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + 'south': [2.137931, 1.645503, 1.320946, 1.107817, 0.993213, 0.945175, + 0.967949, 1.065534, 1.24183, 1.486486, 1.918033, 2.210526], + 'west': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}, + cte.YEAR: {'north': [0], + 'east': [0], + 'south': [1.212544], + 'west': [0]} + } for energy_system in self.energy_systems: if energy_system.generation_system.generic_generation_system.type == cte.PHOTOVOLTAIC: _efficiency = energy_system.generation_system.generic_generation_system.electricity_efficiency self._onsite_electrical_production = {} for _key in self.roofs[0].global_irradiance.keys(): - _results = [0 for _ in range(0, len(self.roofs[0].global_irradiance[_key]))] - for surface in self.surfaces: - _results = [x + y * _efficiency * surface.perimeter_area * surface.solar_collectors_area_reduction_factor - for x, y in zip(_results, surface.global_irradiance[_key])] + _results = [0 for _ in range(0, len(self.roofs[0].global_irradiance[_key][cte.SRA]))] + for surface in self.roofs: + _results = [x + y * _efficiency * surface.perimeter_area + * surface.solar_collectors_area_reduction_factor * z + for x, y, z in zip(_results, surface.global_irradiance[_key][cte.SRA], + orientation_losses_factor[cte.MONTH]['south'])] self._onsite_electrical_production[_key] = _results return self._onsite_electrical_production diff --git a/hub/city_model_structure/building_demand/surface.py b/hub/city_model_structure/building_demand/surface.py index 10e60788..3a8adc9a 100644 --- a/hub/city_model_structure/building_demand/surface.py +++ b/hub/city_model_structure/building_demand/surface.py @@ -359,7 +359,6 @@ class Surface: :return: float """ if self._solar_collectors_area_reduction_factor is None: - _solar_collectors_area_reduction_factor = 0 if self.type == cte.ROOF: _protected_building_restriction = 1 # 10 degrees range @@ -369,12 +368,12 @@ class Surface: _separation_of_panels = 0.46 _shadow_between_panels = 0.7 else: - # pitched + # tilted _construction_restriction = 0.9 _separation_of_panels = 0.9 _shadow_between_panels = 1 - _solar_collectors_area_reduction_factor = _protected_building_restriction * _construction_restriction \ - * _separation_of_panels * _shadow_between_panels + self._solar_collectors_area_reduction_factor = _protected_building_restriction * _construction_restriction \ + * _separation_of_panels * _shadow_between_panels return self._solar_collectors_area_reduction_factor @solar_collectors_area_reduction_factor.setter diff --git a/hub/data/energy_systems/montreal_custom_systems.xml b/hub/data/energy_systems/montreal_custom_systems.xml index b49bbc62..b9eaee8e 100644 --- a/hub/data/energy_systems/montreal_custom_systems.xml +++ b/hub/data/energy_systems/montreal_custom_systems.xml @@ -3,26 +3,32 @@ Fuel-fired water boiler 0.85 + false Electric water boiler 1 + true Fuel-fired furnace and fuel boiler for acs 0.85 + false Electrical furnace and fuel boiler for acs 1 + false Air cooled DX with external condenser 3.23 + false PV system 0.22 + true @@ -78,15 +84,15 @@ Baseboards - 0 + 0 fan-coils - 2 + 2 inductors - 0 + 0 @@ -101,7 +107,6 @@ 1 1 - false 4 pipe fan coils with fuel fired boiler @@ -114,7 +119,6 @@ 1 2 - false 4 pipe fan coils with electrical resistance water boiler @@ -127,7 +131,6 @@ 1 2 - true Single zone packaged rooftop unit with fuel-fired furnace and baseboards and fuel boiler for acs @@ -140,7 +143,6 @@ 5 1 - false Single zone packaged rooftop unit with electrical resistance furnace and baseboards and fuel boiler for acs @@ -153,7 +155,6 @@ 5 1 - false Single zone make-up air unit with baseboard heating with fuel fired boiler @@ -166,7 +167,6 @@ 1 1 - false Single zone make-up air unit with electrical baseboard heating and DHW with resistance @@ -179,7 +179,6 @@ 5 3 - false Multi-zone built-up system with baseboard heater hydronic with fuel fired boiler @@ -192,7 +191,6 @@ 1 3 - false Multi-zone built-up system with electrical baseboard heater and electrical hot water @@ -205,7 +203,6 @@ 1 3 - false Unitary air conditioner air cooled DX with external condenser @@ -217,7 +214,6 @@ 6 3 - false 4 pipe fan coils with water cooled, water chiller @@ -229,7 +225,6 @@ 2 2 - false Single zone packaged rooftop unit with air cooled DX @@ -241,7 +236,6 @@ 6 3 - false Single zone make-up air unit with air cooled DX @@ -253,7 +247,6 @@ 6 3 - false Multi-zone built-up system with water cooled, water chiller @@ -265,7 +258,6 @@ 3 3 - false PV system @@ -277,7 +269,6 @@ 5 3 - true diff --git a/hub/exports/building_energy/insel/insel_monthly_energy_balance.py b/hub/exports/building_energy/insel/insel_monthly_energy_balance.py index c5286e51..241e3bee 100644 --- a/hub/exports/building_energy/insel/insel_monthly_energy_balance.py +++ b/hub/exports/building_energy/insel/insel_monthly_energy_balance.py @@ -24,6 +24,8 @@ _CONSTRUCTION_CODE = { cte.INTERIOR_SLAB: '8' } +_NUMBER_DAYS_PER_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] + class InselMonthlyEnergyBalance(Insel): @@ -252,7 +254,8 @@ class InselMonthlyEnergyBalance(Insel): raise ValueError(f'surface: {surface.name} from building {building.name} has no global irradiance!') global_irradiance = surface.global_irradiance[cte.MONTH] for j in range(0, len(global_irradiance)): - parameters.append(f'{j + 1} {global_irradiance.at[j, radiation_calculation_method]}') + parameters.append(f'{j + 1} ' + f'{global_irradiance.at[j, radiation_calculation_method] / 24 / _NUMBER_DAYS_PER_MONTH[j]}') else: for j in range(0, 12): parameters.append(f'{j + 1} 0.0') diff --git a/hub/helpers/constants.py b/hub/helpers/constants.py index 8b6df87b..9b50cb98 100644 --- a/hub/helpers/constants.py +++ b/hub/helpers/constants.py @@ -182,6 +182,8 @@ ONSITE_ELECTRICITY = 'Onsite Electricity' PHOTOVOLTAIC = 'Photovoltaic' BOILER = 'Boiler' HEAT_PUMP = 'Heat Pump' +BASEBOARD = 'Baseboard' +CHILLER = 'Chiller' # Geometry EPSILON = 0.0000001 diff --git a/hub/helpers/data/montreal_system_to_hub_energy_generation_system.py b/hub/helpers/data/montreal_system_to_hub_energy_generation_system.py index ba68bd47..4e5ce77a 100644 --- a/hub/helpers/data/montreal_system_to_hub_energy_generation_system.py +++ b/hub/helpers/data/montreal_system_to_hub_energy_generation_system.py @@ -11,14 +11,22 @@ import hub.helpers.constants as cte class MontrealSystemToHubEnergyGenerationSystem: def __init__(self): - self._dictionary = {'Fuel-fired water boiler with baseboards': cte.BOILER, - 'Electrical resistance water boiler': cte.BOILER, - 'Fuel-fired furnace and fuel boiler for acs': cte.BOILER, - 'Baseboards: hydronic with fuel boiler': cte.BOILER, - 'Electrical baseboards and electrical boiler for acs': cte.BOILER, - 'Air cooled DX with external condenser': cte.HEAT_PUMP, - 'Water cooled, water chiller': cte.HEAT_PUMP, - 'PV system': cte.PHOTOVOLTAIC + self._dictionary = { + 'Unitary air conditioner with baseboard heater fuel fired boiler': cte.BOILER, + '4 pipe fan coils with fuel fired boiler': cte.BOILER, + '4 pipe fan coils with electrical resistance water boiler': cte.BOILER, + 'Single zone packaged rooftop unit with fuel-fired furnace and baseboards and fuel boiler for acs': cte.BOILER, + 'Single zone packaged rooftop unit with electrical resistance furnace and baseboards and fuel boiler for acs': cte.BOILER, + 'Single zone make-up air unit with baseboard heating with fuel fired boiler': cte.BOILER, + 'Single zone make-up air unit with electrical baseboard heating and DHW with resistance': cte.BASEBOARD, + 'Multi-zone built-up system with baseboard heater hydronic with fuel fired boiler': cte.BOILER, + 'Multi-zone built-up system with electrical baseboard heater and electrical hot water': cte.BASEBOARD, + 'Unitary air conditioner air cooled DX with external condenser': cte.CHILLER, + '4 pipe fan coils with water cooled, water chiller': cte.CHILLER, + 'Single zone packaged rooftop unit with air cooled DX': cte.CHILLER, + 'Single zone make-up air unit with air cooled DX': cte.CHILLER, + 'Multi-zone built-up system with water cooled, water chiller': cte.CHILLER, + 'PV system': cte.PHOTOVOLTAIC } @property diff --git a/hub/imports/energy_systems/montreal_custom_energy_system_parameters.py b/hub/imports/energy_systems/montreal_custom_energy_system_parameters.py index 9ad3ba98..255d3e25 100644 --- a/hub/imports/energy_systems/montreal_custom_energy_system_parameters.py +++ b/hub/imports/energy_systems/montreal_custom_energy_system_parameters.py @@ -52,7 +52,7 @@ class MontrealCustomEnergySystemParameters: building_systems = [] data = [archetype_name, building.name] _energy_systems_connection_table.loc[len(_energy_systems_connection_table)] = data - for equipment in archetype.equipments: + for equipment in archetype.systems: energy_system = GenericEnergySystem() _hub_demand_types = [] for demand_type in equipment.demand_types: diff --git a/hub/imports/results/simplified_radiosity_algorithm.py b/hub/imports/results/simplified_radiosity_algorithm.py index e6f01cf8..fe983216 100644 --- a/hub/imports/results/simplified_radiosity_algorithm.py +++ b/hub/imports/results/simplified_radiosity_algorithm.py @@ -32,17 +32,18 @@ class SimplifiedRadiosityAlgorithm: array = np.concatenate((array, np.full(total_hours, i + 1))) return pd.DataFrame(array, columns=[cte.MONTH]) - def _get_monthly_mean_values(self, values): + def _get_monthly_values(self, values): out = None if values is not None: if cte.MONTH not in values.columns: values = pd.concat([self._month_hour, pd.DataFrame(values)], axis=1) - out = values.groupby(cte.MONTH, as_index=False).mean() + out = values.groupby(cte.MONTH, as_index=False).sum() del out[cte.MONTH] return out - def _get_yearly_mean_values(self, values): - return values.mean() + @staticmethod + def _get_yearly_values(values): + return [values.sum()] def _read_results(self): try: @@ -83,7 +84,7 @@ class SimplifiedRadiosityAlgorithm: surface_id = header_id.split(':')[2] surface = building.surface_by_id(surface_id) new_value = pd.DataFrame(radiation[[header_id]].to_numpy(), columns=[cte.SRA]) - month_new_value = self._get_monthly_mean_values(new_value) + month_new_value = self._get_monthly_values(new_value) if cte.MONTH not in surface.global_irradiance: surface.global_irradiance[cte.MONTH] = month_new_value else: @@ -93,7 +94,7 @@ class SimplifiedRadiosityAlgorithm: else: pd.concat([surface.global_irradiance[cte.HOUR], new_value], axis=1) if cte.YEAR not in surface.global_irradiance: - surface.global_irradiance[cte.YEAR] = self._get_yearly_mean_values(new_value) + surface.global_irradiance[cte.YEAR] = pd.DataFrame(self._get_yearly_values(new_value), columns=[cte.SRA]) self._city.level_of_detail.surface_radiation = 2 for building in self._city.buildings: building.level_of_detail.surface_radiation = 2 diff --git a/hub/unittests/test_systems_catalog.py b/hub/unittests/test_systems_catalog.py index 03702fbd..04833292 100644 --- a/hub/unittests/test_systems_catalog.py +++ b/hub/unittests/test_systems_catalog.py @@ -14,13 +14,16 @@ class TestSystemsCatalog(TestCase): def test_montreal_custom_catalog(self): catalog = EnergySystemsCatalogFactory('montreal_custom').catalog catalog_categories = catalog.names() - for archetype in catalog.entries('archetypes'): - for equipment in archetype.equipments: - print(equipment._equipment_id) archetypes = catalog.names('archetypes') self.assertEqual(18, len(archetypes['archetypes'])) - equipments = catalog.names('equipments') - self.assertEqual(10, len(equipments['equipments'])) + systems = catalog.names('systems') + self.assertEqual(15, len(systems['systems'])) + generation_equipments = catalog.names('generation_equipments') + self.assertEqual(6, len(generation_equipments['generation_equipments'])) + distribution_equipments = catalog.names('distribution_equipments') + self.assertEqual(8, len(distribution_equipments['distribution_equipments'])) + emission_equipments = catalog.names('emission_equipments') + self.assertEqual(3, len(emission_equipments['emission_equipments'])) with self.assertRaises(ValueError): catalog.names('unknown') diff --git a/hub/unittests/test_systems_factory.py b/hub/unittests/test_systems_factory.py index b9395509..e98f6c29 100644 --- a/hub/unittests/test_systems_factory.py +++ b/hub/unittests/test_systems_factory.py @@ -69,7 +69,7 @@ class TestSystemsFactory(TestCase): ResultFactory('insel_monthly_energy_balance', self._city, self._output_path).enrich() for building in self._city.buildings: - building.energy_systems_archetype_name = 'system 1 gas' + building.energy_systems_archetype_name = 'system 1 gas pv' EnergySystemsFactory('montreal_custom', self._city).enrich() # Need to assign energy systems to buildings: energy_systems_connection = self._city.energy_systems_connection_table @@ -107,3 +107,4 @@ class TestSystemsFactory(TestCase): self.assertLess(0, building.heating_consumption[cte.YEAR][0]) self.assertLess(0, building.cooling_consumption[cte.YEAR][0]) self.assertLess(0, building.domestic_hot_water_consumption[cte.YEAR][0]) + self.assertLess(0, building.onsite_electrical_production[cte.YEAR][0])