Merge remote-tracking branch 'origin/systems_catalog' into retrofit_project
This commit is contained in:
commit
48dddae525
|
@ -0,0 +1,42 @@
|
|||
"""
|
||||
Energy System catalog archetype
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2023 Concordia CERC group
|
||||
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
|
||||
|
||||
|
||||
class Archetype:
|
||||
def __init__(self, lod, name, equipments):
|
||||
|
||||
self._lod = lod
|
||||
self._name = name
|
||||
self._equipments = equipments
|
||||
|
||||
@property
|
||||
def lod(self):
|
||||
"""
|
||||
Get level of detail of the catalog
|
||||
:return: string
|
||||
"""
|
||||
return self._lod
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""
|
||||
Get name
|
||||
:return: string
|
||||
"""
|
||||
return f'{self._name}_lod{self._lod}'
|
||||
|
||||
@property
|
||||
def equipments(self) -> List[Equipment]:
|
||||
"""
|
||||
Get list of equipments that compose the total energy system
|
||||
:return: [Equipment]
|
||||
"""
|
||||
return self._equipments
|
26
hub/catalog_factories/data_models/energy_systems/content.py
Normal file
26
hub/catalog_factories/data_models/energy_systems/content.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
"""
|
||||
Energy System catalog content
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2023 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
|
||||
class Content:
|
||||
def __init__(self, archetypes, equipments):
|
||||
self._archetypes = archetypes
|
||||
self._equipments = equipments
|
||||
|
||||
@property
|
||||
def archetypes(self):
|
||||
"""
|
||||
All archetype systems in the catalog
|
||||
"""
|
||||
return self._archetypes
|
||||
|
||||
@property
|
||||
def equipments(self):
|
||||
"""
|
||||
All equipments in the catalog
|
||||
"""
|
||||
return self._equipments
|
|
@ -0,0 +1,48 @@
|
|||
"""
|
||||
Energy System catalog distribution system
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2023 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
|
||||
class DistributionSystem:
|
||||
def __init__(self, system_type, supply_temperature, distribution_consumption,
|
||||
heat_losses):
|
||||
|
||||
self._type = system_type
|
||||
self._supply_temperature = supply_temperature
|
||||
self._distribution_consumption = distribution_consumption
|
||||
self._heat_losses = heat_losses
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
"""
|
||||
Get type from [air, water, refrigerant]
|
||||
:return: string
|
||||
"""
|
||||
return self._type
|
||||
|
||||
@property
|
||||
def supply_temperature(self):
|
||||
"""
|
||||
Get supply_temperature in degree Celsius
|
||||
:return: float
|
||||
"""
|
||||
return self._supply_temperature
|
||||
|
||||
@property
|
||||
def distribution_consumption(self):
|
||||
"""
|
||||
Get distribution_consumption (pump of fan) in ratio over energy produced
|
||||
:return: float
|
||||
"""
|
||||
return self._distribution_consumption
|
||||
|
||||
@property
|
||||
def heat_losses(self):
|
||||
"""
|
||||
Get heat_losses in ratio over energy produced
|
||||
:return: float
|
||||
"""
|
||||
return self._heat_losses
|
|
@ -0,0 +1,28 @@
|
|||
"""
|
||||
Energy System catalog emission system
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2023 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
|
||||
class EmissionSystem:
|
||||
def __init__(self, system_type, parasitic_energy_consumption):
|
||||
self._type = system_type
|
||||
self._parasitic_energy_consumption = parasitic_energy_consumption
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
"""
|
||||
Get type
|
||||
:return: string
|
||||
"""
|
||||
return self._type
|
||||
|
||||
@property
|
||||
def parasitic_energy_consumption(self):
|
||||
"""
|
||||
Get parasitic_energy_consumption in ratio (W/W)
|
||||
:return: float
|
||||
"""
|
||||
return self._parasitic_energy_consumption
|
|
@ -0,0 +1,87 @@
|
|||
"""
|
||||
Energy System catalog equipment
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2023 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
from typing import Union
|
||||
|
||||
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
|
||||
|
||||
|
||||
class Equipment:
|
||||
def __init__(self,
|
||||
lod,
|
||||
equipment_id,
|
||||
name,
|
||||
demand_types,
|
||||
generation_system,
|
||||
distribution_system,
|
||||
emission_system):
|
||||
|
||||
self._lod = lod
|
||||
self._equipment_id = equipment_id
|
||||
self._name = name
|
||||
self._demand_types = demand_types
|
||||
self._generation_system = generation_system
|
||||
self._distribution_system = distribution_system
|
||||
self._emission_system = emission_system
|
||||
|
||||
@property
|
||||
def lod(self):
|
||||
"""
|
||||
Get level of detail of the catalog
|
||||
:return: string
|
||||
"""
|
||||
return self._lod
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
"""
|
||||
Get equipment id
|
||||
:return: string
|
||||
"""
|
||||
return self._equipment_id
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""
|
||||
Get name
|
||||
:return: string
|
||||
"""
|
||||
return f'{self._name}_lod{self._lod}'
|
||||
|
||||
@property
|
||||
def demand_types(self):
|
||||
"""
|
||||
Get demand able to cover from [heating, cooling, domestic_hot_water, electricity]
|
||||
:return: [string]
|
||||
"""
|
||||
return self._demand_types
|
||||
|
||||
@property
|
||||
def generation_system(self) -> GenerationSystem:
|
||||
"""
|
||||
Get generation system
|
||||
:return: GenerationSystem
|
||||
"""
|
||||
return self._generation_system
|
||||
|
||||
@property
|
||||
def distribution_system(self) -> Union[None, DistributionSystem]:
|
||||
"""
|
||||
Get distribution system
|
||||
:return: DistributionSystem
|
||||
"""
|
||||
return self._distribution_system
|
||||
|
||||
@property
|
||||
def emission_system(self) -> Union[None, EmissionSystem]:
|
||||
"""
|
||||
Get emission system
|
||||
:return: EmissionSystem
|
||||
"""
|
||||
return self._emission_system
|
|
@ -0,0 +1,105 @@
|
|||
"""
|
||||
Energy System catalog generation system
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2023 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
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):
|
||||
|
||||
self._type = system_type
|
||||
self._fuel_type = fuel_type
|
||||
self._source_types = source_types
|
||||
self._heat_efficiency = heat_efficiency
|
||||
self._cooling_efficiency = cooling_efficiency
|
||||
self._electricity_efficiency = electricity_efficiency
|
||||
self._source_temperature = source_temperature
|
||||
self._source_mass_flow = source_mass_flow
|
||||
self._storage = storage
|
||||
self._auxiliary_equipment = auxiliary_equipment
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
"""
|
||||
Get type
|
||||
:return: string
|
||||
"""
|
||||
return self._type
|
||||
|
||||
@property
|
||||
def fuel_type(self):
|
||||
"""
|
||||
Get fuel_type from [renewable, gas, diesel, electricity, wood, coal]
|
||||
:return: string
|
||||
"""
|
||||
return self._fuel_type
|
||||
|
||||
@property
|
||||
def source_types(self):
|
||||
"""
|
||||
Get source_type from [air, water, geothermal, district_heating, grid, on_site_electricity]
|
||||
:return: [string]
|
||||
"""
|
||||
return self._source_types
|
||||
|
||||
@property
|
||||
def heat_efficiency(self):
|
||||
"""
|
||||
Get heat_efficiency
|
||||
:return: float
|
||||
"""
|
||||
return self._heat_efficiency
|
||||
|
||||
@property
|
||||
def cooling_efficiency(self):
|
||||
"""
|
||||
Get cooling_efficiency
|
||||
:return: float
|
||||
"""
|
||||
return self._cooling_efficiency
|
||||
|
||||
@property
|
||||
def electricity_efficiency(self):
|
||||
"""
|
||||
Get electricity_efficiency
|
||||
:return: float
|
||||
"""
|
||||
return self._electricity_efficiency
|
||||
|
||||
@property
|
||||
def source_temperature(self):
|
||||
"""
|
||||
Get source_temperature in degree Celsius
|
||||
:return: float
|
||||
"""
|
||||
return self._source_temperature
|
||||
|
||||
@property
|
||||
def source_mass_flow(self):
|
||||
"""
|
||||
Get source_mass_flow in kg/s
|
||||
:return: float
|
||||
"""
|
||||
return self._source_mass_flow
|
||||
|
||||
@property
|
||||
def storage(self):
|
||||
"""
|
||||
Get boolean storage exists
|
||||
:return: bool
|
||||
"""
|
||||
return self._storage
|
||||
|
||||
@property
|
||||
def auxiliary_equipment(self) -> Union[None, GenerationSystem]:
|
||||
"""
|
||||
Get auxiliary_equipment
|
||||
:return: GenerationSystem
|
||||
"""
|
||||
return self._auxiliary_equipment
|
144
hub/catalog_factories/energy_systems/montreal_custom_catalog.py
Normal file
144
hub/catalog_factories/energy_systems/montreal_custom_catalog.py
Normal file
|
@ -0,0 +1,144 @@
|
|||
"""
|
||||
Montreal custom energy systems 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 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.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.archetype import Archetype
|
||||
|
||||
|
||||
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=('equipment', 'system', 'demand', 'equipment_id'))
|
||||
|
||||
self._lod = float(self._archetypes['catalog']['@lod'])
|
||||
|
||||
self._catalog_equipments = self._load_equipments()
|
||||
self._catalog_archetypes = self._load_archetypes()
|
||||
|
||||
# store the full catalog data model in self._content
|
||||
self._content = Content(self._catalog_archetypes,
|
||||
self._catalog_equipments)
|
||||
|
||||
def _load_equipments(self):
|
||||
_catalog_equipments = []
|
||||
equipments = self._archetypes['catalog']['equipments']['equipment']
|
||||
for equipment in equipments:
|
||||
equipment_id = float(equipment['@id'])
|
||||
equipment_type = equipment['@type']
|
||||
fuel_type = equipment['@fuel_type']
|
||||
name = equipment['name']
|
||||
demands = equipment['demands']['demand']
|
||||
heating_efficiency = None
|
||||
if 'heating_efficiency' in equipment:
|
||||
heating_efficiency = float(equipment['heating_efficiency'])
|
||||
cooling_efficiency = None
|
||||
if 'cooling_efficiency' in equipment:
|
||||
cooling_efficiency = float(equipment['cooling_efficiency'])
|
||||
electricity_efficiency = None
|
||||
if 'electricity_efficiency' in equipment:
|
||||
electricity_efficiency = float(equipment['electricity_efficiency'])
|
||||
distribution_heat_losses = None
|
||||
if 'distribution_heat_losses' in equipment:
|
||||
distribution_heat_losses = float(equipment['distribution_heat_losses']['#text']) / 100
|
||||
distribution_consumption = None
|
||||
if 'distribution_consumption' in equipment:
|
||||
distribution_consumption = float(equipment['distribution_consumption']['#text']) / 100
|
||||
storage = eval(equipment['storage'].capitalize())
|
||||
generation_system = GenerationSystem(equipment_type,
|
||||
fuel_type,
|
||||
None,
|
||||
heating_efficiency,
|
||||
cooling_efficiency,
|
||||
electricity_efficiency,
|
||||
None,
|
||||
None,
|
||||
storage,
|
||||
None)
|
||||
distribution_system = DistributionSystem(None,
|
||||
None,
|
||||
distribution_consumption,
|
||||
distribution_heat_losses)
|
||||
_catalog_equipments.append(Equipment(self._lod,
|
||||
equipment_id,
|
||||
name,
|
||||
demands,
|
||||
generation_system,
|
||||
distribution_system,
|
||||
None))
|
||||
return _catalog_equipments
|
||||
|
||||
def _load_archetypes(self):
|
||||
_catalog_archetypes = []
|
||||
systems = self._archetypes['catalog']['systems']['system']
|
||||
for system in systems:
|
||||
name = system['@name']
|
||||
system_equipments = system['equipments']['equipment_id']
|
||||
_equipments = []
|
||||
for system_equipment in system_equipments:
|
||||
for equipment in self._catalog_equipments:
|
||||
if int(equipment.id) == int(system_equipment):
|
||||
_equipments.append(equipment)
|
||||
_catalog_archetypes.append(Archetype(self._lod, name, _equipments))
|
||||
return _catalog_archetypes
|
||||
|
||||
def names(self, category=None):
|
||||
"""
|
||||
Get the catalog elements names
|
||||
:parm: optional category filter
|
||||
"""
|
||||
if category is None:
|
||||
_names = {'archetypes': [], 'equipments': []}
|
||||
for archetype in self._content.archetypes:
|
||||
_names['archetypes'].append(archetype.name)
|
||||
for equipment in self._content.equipments:
|
||||
_names['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() == 'equipments':
|
||||
for equipment in self._content.equipments:
|
||||
_names[category].append(equipment.name)
|
||||
else:
|
||||
raise ValueError(f'Unknown category [{category}]')
|
||||
return _names
|
||||
|
||||
def entries(self, category=None):
|
||||
"""
|
||||
Get the catalog elements
|
||||
:parm: optional category filter
|
||||
"""
|
||||
if category is None:
|
||||
return self._content
|
||||
else:
|
||||
if category.lower() == 'archetypes':
|
||||
return self._content.archetypes
|
||||
elif category.lower() == 'equipments':
|
||||
return self._content.equipments
|
||||
else:
|
||||
raise ValueError(f'Unknown category [{category}]')
|
||||
|
||||
def get_entry(self, name):
|
||||
"""
|
||||
Get one catalog element by names
|
||||
:parm: entry name
|
||||
"""
|
||||
for entry in self._content.archetypes:
|
||||
if entry.name.lower() == name.lower():
|
||||
return entry
|
||||
for entry in self._content.equipments:
|
||||
if entry.name.lower() == name.lower():
|
||||
return entry
|
||||
raise IndexError(f"{name} doesn't exists in the catalog")
|
|
@ -1,190 +0,0 @@
|
|||
"""
|
||||
NRCAN energy systems 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 hub.helpers.constants as cte
|
||||
from hub.catalog_factories.catalog import Catalog
|
||||
from hub.catalog_factories.data_models.usages.appliances import Appliances
|
||||
from hub.catalog_factories.data_models.usages.content import Content
|
||||
from hub.catalog_factories.data_models.usages.lighting import Lighting
|
||||
from hub.catalog_factories.data_models.usages.ocupancy import Occupancy
|
||||
from hub.catalog_factories.data_models.usages.schedule import Schedule
|
||||
from hub.catalog_factories.data_models.usages.thermal_control import ThermalControl
|
||||
from hub.catalog_factories.data_models.usages.usage import Usage
|
||||
from hub.catalog_factories.usage.usage_helper import UsageHelper
|
||||
|
||||
|
||||
class NrcanCatalog(Catalog):
|
||||
def __init__(self, path):
|
||||
path = str(path / 'nrcan.xml')
|
||||
self._content = None
|
||||
self._schedules = {}
|
||||
with open(path) as xml:
|
||||
self._metadata = xmltodict.parse(xml.read())
|
||||
self._base_url = self._metadata['nrcan']['@base_url']
|
||||
self._load_schedules()
|
||||
self._content = Content(self._load_archetypes())
|
||||
|
||||
def _load_archetypes(self):
|
||||
usages = []
|
||||
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['space_type'] == 'WholeBuilding']
|
||||
for space_type in space_types:
|
||||
# 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']
|
||||
hvac_schedule_name = space_type['exhaust_schedule']
|
||||
if 'FAN' in hvac_schedule_name:
|
||||
hvac_schedule_name = hvac_schedule_name.replace('FAN', 'Fan')
|
||||
#todo: get -1 out of the setpoint
|
||||
heating_setpoint_schedule_name = space_type['heating_setpoint_schedule']-1
|
||||
cooling_setpoint_schedule_name = space_type['cooling_setpoint_schedule']
|
||||
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']
|
||||
|
||||
# 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
|
||||
# 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_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,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
occupancy_schedule)
|
||||
lighting = Lighting(lighting_density,
|
||||
lighting_convective_fraction,
|
||||
lighting_radiative_fraction,
|
||||
lighting_latent_fraction,
|
||||
lighting_schedule)
|
||||
appliances = Appliances(appliances_density,
|
||||
appliances_convective_fraction,
|
||||
appliances_radiative_fraction,
|
||||
appliances_latent_fraction,
|
||||
appliance_schedule)
|
||||
thermal_control = ThermalControl(None,
|
||||
None,
|
||||
None,
|
||||
hvac_availability,
|
||||
heating_schedule,
|
||||
cooling_schedule)
|
||||
hours_day = None
|
||||
days_year = None
|
||||
usages.append(Usage(usage_type,
|
||||
hours_day,
|
||||
days_year,
|
||||
mechanical_air_change,
|
||||
ventilation_rate,
|
||||
occupancy,
|
||||
lighting,
|
||||
appliances,
|
||||
thermal_control))
|
||||
return usages
|
||||
|
||||
def names(self, category=None):
|
||||
"""
|
||||
Get the catalog elements names
|
||||
:parm: optional category filter
|
||||
"""
|
||||
if category is None:
|
||||
_names = {'archetypes': [], 'constructions': [], 'materials': [], 'windows': []}
|
||||
for archetype in self._content.archetypes:
|
||||
_names['archetypes'].append(archetype.name)
|
||||
for construction in self._content.constructions:
|
||||
_names['constructions'].append(construction.name)
|
||||
for material in self._content.materials:
|
||||
_names['materials'].append(material.name)
|
||||
for window in self._content.windows:
|
||||
_names['windows'].append(window.name)
|
||||
else:
|
||||
_names = {category: []}
|
||||
if category.lower() == 'archetypes':
|
||||
for archetype in self._content.archetypes:
|
||||
_names[category].append(archetype.name)
|
||||
elif category.lower() == 'constructions':
|
||||
for construction in self._content.constructions:
|
||||
_names[category].append(construction.name)
|
||||
elif category.lower() == 'materials':
|
||||
for material in self._content.materials:
|
||||
_names[category].append(material.name)
|
||||
elif category.lower() == 'windows':
|
||||
for window in self._content.windows:
|
||||
_names[category].append(window.name)
|
||||
else:
|
||||
raise ValueError(f'Unknown category [{category}]')
|
||||
|
||||
def entries(self, category=None):
|
||||
"""
|
||||
Get the catalog elements
|
||||
:parm: optional category filter
|
||||
"""
|
||||
if category is None:
|
||||
return self._content
|
||||
else:
|
||||
if category.lower() == 'archetypes':
|
||||
return self._content.archetypes
|
||||
elif category.lower() == 'constructions':
|
||||
return self._content.constructions
|
||||
elif category.lower() == 'materials':
|
||||
return self._content.materials
|
||||
elif category.lower() == 'windows':
|
||||
return self._content.windows
|
||||
else:
|
||||
raise ValueError(f'Unknown category [{category}]')
|
||||
|
||||
def get_entry(self, name):
|
||||
"""
|
||||
Get one catalog element by names
|
||||
:parm: entry name
|
||||
"""
|
||||
for entry in self._content.archetypes:
|
||||
if entry.name.lower() == name.lower():
|
||||
return entry
|
||||
for entry in self._content.constructions:
|
||||
if entry.name.lower() == name.lower():
|
||||
return entry
|
||||
for entry in self._content.materials:
|
||||
if entry.name.lower() == name.lower():
|
||||
return entry
|
||||
for entry in self._content.windows:
|
||||
if entry.name.lower() == name.lower():
|
||||
return entry
|
||||
raise IndexError(f"{name} doesn't exists in the catalog")
|
|
@ -1,5 +1,5 @@
|
|||
"""
|
||||
Usage catalog factory, publish the usage information
|
||||
Energy Systems catalog factory, publish the energy systems information
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Álvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
|
@ -7,18 +7,18 @@ Project Coder Pilar Monsalvete Álvarez de Uribarri pilar.monsalvete@concordia.c
|
|||
|
||||
from pathlib import Path
|
||||
from typing import TypeVar
|
||||
from hub.catalog_factories.energy_systems.nrcan_catalog import NrcanCatalog
|
||||
from hub.catalog_factories.energy_systems.montreal_custom_catalog import MontrealCustomCatalog
|
||||
from hub.hub_logger import logger
|
||||
from hub.helpers.utils import validate_import_export_type
|
||||
Catalog = TypeVar('Catalog')
|
||||
|
||||
|
||||
class UsageCatalogFactory:
|
||||
class EnergySystemsCatalogFactory:
|
||||
def __init__(self, file_type, base_path=None):
|
||||
if base_path is None:
|
||||
base_path = Path(Path(__file__).parent.parent / 'data/energy_systems')
|
||||
self._catalog_type = '_' + file_type.lower()
|
||||
class_funcs = validate_import_export_type(UsageCatalogFactory)
|
||||
class_funcs = validate_import_export_type(EnergySystemsCatalogFactory)
|
||||
if self._catalog_type not in class_funcs:
|
||||
err_msg = f"Wrong import type. Valid functions include {class_funcs}"
|
||||
logger.error(err_msg)
|
||||
|
@ -26,12 +26,11 @@ class UsageCatalogFactory:
|
|||
self._path = base_path
|
||||
|
||||
@property
|
||||
def _nrcan(self):
|
||||
def _montreal_custom(self):
|
||||
"""
|
||||
Retrieve NRCAN catalog
|
||||
"""
|
||||
# nrcan retrieves the data directly from github
|
||||
return NrcanCatalog(self._path)
|
||||
return MontrealCustomCatalog(self._path)
|
||||
|
||||
@property
|
||||
def catalog(self) -> Catalog:
|
||||
|
|
|
@ -13,12 +13,13 @@ import pandas as pd
|
|||
|
||||
from hub.hub_logger import logger
|
||||
import hub.helpers.constants as cte
|
||||
import hub.helpers.peak_loads as pl
|
||||
from hub.helpers.peak_loads import PeakLoads
|
||||
from hub.city_model_structure.building_demand.surface import Surface
|
||||
from hub.city_model_structure.city_object import CityObject
|
||||
from hub.city_model_structure.building_demand.household import Household
|
||||
from hub.city_model_structure.building_demand.internal_zone import InternalZone
|
||||
from hub.city_model_structure.attributes.polyhedron import Polyhedron
|
||||
from hub.city_model_structure.energy_systems.energy_system import EnergySystem
|
||||
|
||||
|
||||
class Building(CityObject):
|
||||
|
@ -47,7 +48,13 @@ class Building(CityObject):
|
|||
self._lighting_electrical_demand = dict()
|
||||
self._appliances_electrical_demand = dict()
|
||||
self._domestic_hot_water_heat_demand = dict()
|
||||
self._heating_consumption = dict()
|
||||
self._cooling_consumption = dict()
|
||||
self._domestic_hot_water_consumption = dict()
|
||||
self._onsite_electrical_production = dict()
|
||||
self._eave_height = None
|
||||
self._energy_systems = None
|
||||
self._systems_archetype_name = None
|
||||
self._grounds = []
|
||||
self._roofs = []
|
||||
self._walls = []
|
||||
|
@ -193,14 +200,6 @@ class Building(CityObject):
|
|||
if value is not None:
|
||||
self._basement_heated = int(value)
|
||||
|
||||
@property
|
||||
def heated_volume(self):
|
||||
"""
|
||||
Raises not implemented error
|
||||
"""
|
||||
# todo: this need to be calculated based on the basement and attic heated values
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
def year_of_construction(self):
|
||||
"""
|
||||
|
@ -366,31 +365,38 @@ class Building(CityObject):
|
|||
self._domestic_hot_water_heat_demand = value
|
||||
|
||||
@property
|
||||
def heating_peak_load(self) -> dict:
|
||||
def heating_peak_load(self) -> Union[None, dict]:
|
||||
"""
|
||||
Get heating peak load in W
|
||||
:return: dict{DataFrame(float)}
|
||||
"""
|
||||
results = {}
|
||||
if cte.HOUR in self.heating:
|
||||
monthly_values = pl.peak_loads_from_hourly(self.heating[cte.HOUR][next(iter(self.heating[cte.HOUR]))].values)
|
||||
monthly_values = PeakLoads().\
|
||||
peak_loads_from_hourly(self.heating[cte.HOUR][next(iter(self.heating[cte.HOUR]))].values)
|
||||
else:
|
||||
monthly_values = pl.heating_peak_loads_from_methodology(self)
|
||||
monthly_values = PeakLoads(self).heating_peak_loads_from_methodology
|
||||
if monthly_values is None:
|
||||
return None
|
||||
results[cte.MONTH] = pd.DataFrame(monthly_values, columns=['heating peak loads'])
|
||||
results[cte.YEAR] = pd.DataFrame([max(monthly_values)], columns=['heating peak loads'])
|
||||
return results
|
||||
|
||||
@property
|
||||
def cooling_peak_load(self) -> dict:
|
||||
def cooling_peak_load(self) -> Union[None, dict]:
|
||||
"""
|
||||
Get cooling peak load in W
|
||||
:return: dict{DataFrame(float)}
|
||||
"""
|
||||
results = {}
|
||||
monthly_values = None
|
||||
if cte.HOUR in self.cooling:
|
||||
monthly_values = pl.peak_loads_from_hourly(self.cooling[cte.HOUR][next(iter(self.cooling[cte.HOUR]))])
|
||||
# todo: .values???????? Like heating
|
||||
monthly_values = PeakLoads().peak_loads_from_hourly(self.cooling[cte.HOUR][next(iter(self.cooling[cte.HOUR]))])
|
||||
else:
|
||||
monthly_values = pl.cooling_peak_loads_from_methodology(self)
|
||||
monthly_values = PeakLoads(self).cooling_peak_loads_from_methodology
|
||||
if monthly_values is None:
|
||||
return None
|
||||
results[cte.MONTH] = pd.DataFrame(monthly_values, columns=['cooling peak loads'])
|
||||
results[cte.YEAR] = pd.DataFrame([max(monthly_values)], columns=['cooling peak loads'])
|
||||
return results
|
||||
|
@ -491,3 +497,118 @@ class Building(CityObject):
|
|||
for usage in internal_zone.usages:
|
||||
_usage = f'{_usage}{usage.name}_{usage.percentage} '
|
||||
return _usage.rstrip()
|
||||
|
||||
@property
|
||||
def energy_systems(self) -> Union[None, List[EnergySystem]]:
|
||||
"""
|
||||
Get list of energy systems installed to cover the building demands
|
||||
:return: [EnergySystem]
|
||||
"""
|
||||
return self._energy_systems
|
||||
|
||||
@energy_systems.setter
|
||||
def energy_systems(self, value):
|
||||
"""
|
||||
Set list of energy systems installed to cover the building demands
|
||||
:param value: [EnergySystem]
|
||||
"""
|
||||
self._energy_systems = value
|
||||
|
||||
@property
|
||||
def energy_systems_archetype_name(self):
|
||||
"""
|
||||
Get energy systems archetype name
|
||||
:return: str
|
||||
"""
|
||||
return self._systems_archetype_name
|
||||
|
||||
@energy_systems_archetype_name.setter
|
||||
def energy_systems_archetype_name(self, value):
|
||||
"""
|
||||
Set energy systems archetype name
|
||||
:param value: str
|
||||
"""
|
||||
self._systems_archetype_name = value
|
||||
|
||||
@property
|
||||
def heating_consumption(self):
|
||||
"""
|
||||
Get energy consumption for heating according to the heating system installed
|
||||
return: dict
|
||||
"""
|
||||
if len(self._heating_consumption) == 0:
|
||||
for heating_demand_key in self.heating:
|
||||
demand = self.heating[heating_demand_key][cte.INSEL_MEB]
|
||||
consumption_type = cte.HEATING
|
||||
final_energy_consumed = self._calculate_consumption(consumption_type, demand)
|
||||
self._heating_consumption[heating_demand_key] = final_energy_consumed
|
||||
return self._heating_consumption
|
||||
|
||||
@property
|
||||
def cooling_consumption(self):
|
||||
"""
|
||||
Get energy consumption for cooling according to the cooling system installed
|
||||
return: dict
|
||||
"""
|
||||
if len(self._cooling_consumption) == 0:
|
||||
for cooling_demand_key in self.cooling:
|
||||
demand = self.cooling[cooling_demand_key][cte.INSEL_MEB]
|
||||
consumption_type = cte.COOLING
|
||||
final_energy_consumed = self._calculate_consumption(consumption_type, demand)
|
||||
self._cooling_consumption[cooling_demand_key] = final_energy_consumed
|
||||
return self._cooling_consumption
|
||||
|
||||
@property
|
||||
def domestic_hot_water_consumption(self):
|
||||
"""
|
||||
Get energy consumption for domestic according to the domestic hot water system installed
|
||||
return: dict
|
||||
"""
|
||||
if len(self._domestic_hot_water_consumption) == 0:
|
||||
for domestic_hot_water_demand_key in self.domestic_hot_water_heat_demand:
|
||||
demand = self.domestic_hot_water_heat_demand[domestic_hot_water_demand_key][cte.INSEL_MEB]
|
||||
consumption_type = cte.DOMESTIC_HOT_WATER
|
||||
final_energy_consumed = self._calculate_consumption(consumption_type, demand)
|
||||
self._domestic_hot_water_consumption[domestic_hot_water_demand_key] = final_energy_consumed
|
||||
return self._domestic_hot_water_consumption
|
||||
|
||||
def _calculate_consumption(self, consumption_type, demand):
|
||||
# todo: modify when COP depends on the hour
|
||||
coefficient_of_performance = 0
|
||||
for energy_system in self.energy_systems:
|
||||
for demand_type in energy_system.demand_types:
|
||||
if demand_type.lower() == consumption_type.lower():
|
||||
if consumption_type == cte.HEATING or consumption_type == cte.DOMESTIC_HOT_WATER:
|
||||
coefficient_of_performance = energy_system.generation_system.generic_generation_system.heat_efficiency
|
||||
elif consumption_type == cte.COOLING:
|
||||
coefficient_of_performance = energy_system.generation_system.generic_generation_system.cooling_efficiency
|
||||
elif consumption_type == cte.ELECTRICITY:
|
||||
coefficient_of_performance = \
|
||||
energy_system.generation_system.generic_generation_system.electricity_efficiency
|
||||
if coefficient_of_performance == 0:
|
||||
values = [0]*len(demand)
|
||||
final_energy_consumed = values
|
||||
else:
|
||||
final_energy_consumed = []
|
||||
for demand_value in demand:
|
||||
final_energy_consumed.append(demand_value / coefficient_of_performance)
|
||||
return final_energy_consumed
|
||||
|
||||
@property
|
||||
def onsite_electrical_production(self):
|
||||
"""
|
||||
Get total electricity produced onsite
|
||||
return: dict
|
||||
"""
|
||||
# Add other systems whenever new ones appear
|
||||
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])]
|
||||
self._onsite_electrical_production[_key] = _results
|
||||
return self._onsite_electrical_production
|
||||
|
|
|
@ -7,6 +7,8 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord
|
|||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
import uuid
|
||||
import numpy as np
|
||||
from typing import List, Union
|
||||
|
@ -42,6 +44,7 @@ class Surface:
|
|||
self._associated_thermal_boundaries = []
|
||||
self._vegetation = None
|
||||
self._percentage_shared = None
|
||||
self._solar_collectors_area_reduction_factor = None
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
|
@ -134,7 +137,7 @@ class Surface:
|
|||
@property
|
||||
def azimuth(self):
|
||||
"""
|
||||
Get surface azimuth in radians
|
||||
Get surface azimuth in radians (north = 0)
|
||||
:return: float
|
||||
"""
|
||||
if self._azimuth is None:
|
||||
|
@ -145,7 +148,7 @@ class Surface:
|
|||
@property
|
||||
def inclination(self):
|
||||
"""
|
||||
Get surface inclination in radians
|
||||
Get surface inclination in radians (zenith = 0, horizon = pi/2)
|
||||
:return: float
|
||||
"""
|
||||
if self._inclination is None:
|
||||
|
@ -161,10 +164,12 @@ class Surface:
|
|||
:return: str
|
||||
"""
|
||||
if self._type is None:
|
||||
grad = np.rad2deg(self.inclination)
|
||||
if grad >= 170:
|
||||
inclination_cos = math.cos(self.inclination)
|
||||
# 170 degrees
|
||||
if inclination_cos <= -0.98:
|
||||
self._type = 'Ground'
|
||||
elif 80 <= grad <= 100:
|
||||
# between 80 and 100 degrees
|
||||
elif abs(inclination_cos) <= 0.17:
|
||||
self._type = 'Wall'
|
||||
else:
|
||||
self._type = 'Roof'
|
||||
|
@ -346,3 +351,36 @@ class Surface:
|
|||
:param value: float
|
||||
"""
|
||||
self._percentage_shared = value
|
||||
|
||||
@property
|
||||
def solar_collectors_area_reduction_factor(self):
|
||||
"""
|
||||
Get factor area collector per surface area if set or calculate using Romero Rodríguez, L. et al (2017) model if not
|
||||
: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
|
||||
if abs(math.sin(self.inclination)) < 0.17:
|
||||
# horizontal
|
||||
_construction_restriction = 0.8
|
||||
_separation_of_panels = 0.46
|
||||
_shadow_between_panels = 0.7
|
||||
else:
|
||||
# pitched
|
||||
_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
|
||||
return self._solar_collectors_area_reduction_factor
|
||||
|
||||
@solar_collectors_area_reduction_factor.setter
|
||||
def solar_collectors_area_reduction_factor(self, value):
|
||||
"""
|
||||
Set factor area collector per surface area
|
||||
:param value: float
|
||||
"""
|
||||
self._solar_collectors_area_reduction_factor = value
|
||||
|
|
|
@ -16,6 +16,7 @@ import pyproj
|
|||
from typing import List, Union
|
||||
from pyproj import Transformer
|
||||
from pathlib import Path
|
||||
from pandas import DataFrame
|
||||
from hub.city_model_structure.building import Building
|
||||
from hub.city_model_structure.city_object import CityObject
|
||||
from hub.city_model_structure.city_objects_cluster import CityObjectsCluster
|
||||
|
@ -61,6 +62,8 @@ class City:
|
|||
self._lca_materials = None
|
||||
self._level_of_detail = LevelOfDetail()
|
||||
self._city_objects_dictionary = {}
|
||||
self._energy_systems_connection_table = None
|
||||
self._generic_energy_systems = None
|
||||
|
||||
@property
|
||||
def fuels(self) -> [Fuel]:
|
||||
|
@ -490,4 +493,36 @@ class City:
|
|||
"""
|
||||
return self._level_of_detail
|
||||
|
||||
@property
|
||||
def energy_systems_connection_table(self) -> Union[None, DataFrame]:
|
||||
"""
|
||||
Get energy systems connection table which includes at least two columns: energy_system_type and associated_building
|
||||
and may also include dimensioned_energy_system and connection_building_to_dimensioned_energy_system
|
||||
:return: DataFrame
|
||||
"""
|
||||
return self._energy_systems_connection_table
|
||||
|
||||
@energy_systems_connection_table.setter
|
||||
def energy_systems_connection_table(self, value):
|
||||
"""
|
||||
Set energy systems connection table which includes at least two columns: energy_system_type and associated_building
|
||||
and may also include dimensioned_energy_system and connection_building_to_dimensioned_energy_system
|
||||
:param value: DataFrame
|
||||
"""
|
||||
self._energy_systems_connection_table = value
|
||||
|
||||
@property
|
||||
def generic_energy_systems(self) -> dict:
|
||||
"""
|
||||
Get dictionary with generic energy systems installed in the city
|
||||
:return: dict
|
||||
"""
|
||||
return self._generic_energy_systems
|
||||
|
||||
@generic_energy_systems.setter
|
||||
def generic_energy_systems(self, value):
|
||||
"""
|
||||
Set dictionary with generic energy systems installed in the city
|
||||
:return: dict
|
||||
"""
|
||||
self._generic_energy_systems = value
|
||||
|
|
|
@ -8,6 +8,7 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
|||
from __future__ import annotations
|
||||
from typing import List, Union
|
||||
|
||||
from hub.city_model_structure.level_of_detail import LevelOfDetail
|
||||
from hub.city_model_structure.iot.sensor import Sensor
|
||||
from hub.city_model_structure.building_demand.surface import Surface
|
||||
from hub.city_model_structure.attributes.polyhedron import Polyhedron
|
||||
|
@ -21,6 +22,7 @@ class CityObject:
|
|||
"""
|
||||
def __init__(self, name, surfaces):
|
||||
self._name = name
|
||||
self._level_of_detail = LevelOfDetail()
|
||||
self._surfaces = surfaces
|
||||
self._type = None
|
||||
self._city_object_lower_corner = None
|
||||
|
@ -43,6 +45,14 @@ class CityObject:
|
|||
self._sensors = []
|
||||
self._neighbours = None
|
||||
|
||||
@property
|
||||
def level_of_detail(self) -> LevelOfDetail:
|
||||
"""
|
||||
Get level of detail of different aspects of the city: geometry, construction and usage
|
||||
:return: LevelOfDetail
|
||||
"""
|
||||
return self._level_of_detail
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""
|
||||
|
|
30
hub/city_model_structure/energy_systems/control_system.py
Normal file
30
hub/city_model_structure/energy_systems/control_system.py
Normal file
|
@ -0,0 +1,30 @@
|
|||
"""
|
||||
Energy control system definition
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2023 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
|
||||
class ControlSystem:
|
||||
"""
|
||||
ControlSystem class
|
||||
"""
|
||||
def __init__(self):
|
||||
self._control_type = None
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
"""
|
||||
Get control type
|
||||
:return: string
|
||||
"""
|
||||
return self._control_type
|
||||
|
||||
@type.setter
|
||||
def type(self, value):
|
||||
"""
|
||||
Set control type
|
||||
:param value: string
|
||||
"""
|
||||
self._control_type = value
|
|
@ -0,0 +1,32 @@
|
|||
"""
|
||||
Energy distribution system definition
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2023 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
from hub.city_model_structure.energy_systems.generic_distribution_system import GenericDistributionSystem
|
||||
|
||||
|
||||
class DistributionSystem:
|
||||
"""
|
||||
DistributionSystem class
|
||||
"""
|
||||
def __init__(self):
|
||||
self._generic_distribution_system = None
|
||||
|
||||
@property
|
||||
def generic_distribution_system(self) -> GenericDistributionSystem:
|
||||
"""
|
||||
Get generic_distribution_system
|
||||
:return: GenericDistributionSystem
|
||||
"""
|
||||
return self._generic_distribution_system
|
||||
|
||||
@generic_distribution_system.setter
|
||||
def generic_distribution_system(self, value):
|
||||
"""
|
||||
Set associated generic_distribution_system
|
||||
:param value: GenericDistributionSystem
|
||||
"""
|
||||
self._generic_distribution_system = value
|
32
hub/city_model_structure/energy_systems/emission_system.py
Normal file
32
hub/city_model_structure/energy_systems/emission_system.py
Normal file
|
@ -0,0 +1,32 @@
|
|||
"""
|
||||
Energy emission system definition
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2023 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
from hub.city_model_structure.energy_systems.generic_emission_system import GenericEmissionSystem
|
||||
|
||||
|
||||
class EmissionSystem:
|
||||
"""
|
||||
EmissionSystem class
|
||||
"""
|
||||
def __init__(self):
|
||||
self._generic_emission_system = None
|
||||
|
||||
@property
|
||||
def generic_emission_system(self) -> GenericEmissionSystem:
|
||||
"""
|
||||
Get associated generic_emission_system
|
||||
:return: GenericEmissionSystem
|
||||
"""
|
||||
return self._generic_emission_system
|
||||
|
||||
@generic_emission_system.setter
|
||||
def generic_emission_system(self, value):
|
||||
"""
|
||||
Set associated
|
||||
:param value: GenericEmissionSystem
|
||||
"""
|
||||
self._generic_emission_system = value
|
124
hub/city_model_structure/energy_systems/energy_system.py
Normal file
124
hub/city_model_structure/energy_systems/energy_system.py
Normal file
|
@ -0,0 +1,124 @@
|
|||
"""
|
||||
Energy system definition
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2023 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
from typing import Union, List
|
||||
|
||||
from hub.city_model_structure.energy_systems.generic_energy_system import GenericEnergySystem
|
||||
from hub.city_model_structure.energy_systems.generation_system import GenerationSystem
|
||||
from hub.city_model_structure.energy_systems.distribution_system import DistributionSystem
|
||||
from hub.city_model_structure.energy_systems.emission_system import EmissionSystem
|
||||
from hub.city_model_structure.energy_systems.control_system import ControlSystem
|
||||
from hub.city_model_structure.city_object import CityObject
|
||||
|
||||
|
||||
class EnergySystem:
|
||||
"""
|
||||
EnergySystem class
|
||||
"""
|
||||
def __init__(self):
|
||||
self._generic_energy_system = None
|
||||
self._generation_system = None
|
||||
self._distribution_system = None
|
||||
self._emission_system = None
|
||||
self._connected_city_objects = None
|
||||
self._control_system = None
|
||||
|
||||
@property
|
||||
def generic_energy_system(self) -> GenericEnergySystem:
|
||||
"""
|
||||
Get associated generic_energy_system
|
||||
:return: GenericEnergySystem
|
||||
"""
|
||||
return self._generic_energy_system
|
||||
|
||||
@generic_energy_system.setter
|
||||
def generic_energy_system(self, value):
|
||||
"""
|
||||
Set associated generic_energy_system
|
||||
:param value: GenericEnergySystem
|
||||
"""
|
||||
self._generic_energy_system = value
|
||||
|
||||
@property
|
||||
def generation_system(self) -> GenerationSystem:
|
||||
"""
|
||||
Get generation system
|
||||
:return: GenerationSystem
|
||||
"""
|
||||
return self._generation_system
|
||||
|
||||
@generation_system.setter
|
||||
def generation_system(self, value):
|
||||
"""
|
||||
Set generation system
|
||||
:param value: GenerationSystem
|
||||
"""
|
||||
self._generation_system = value
|
||||
|
||||
@property
|
||||
def distribution_system(self) -> Union[None, DistributionSystem]:
|
||||
"""
|
||||
Get distribution system
|
||||
:return: DistributionSystem
|
||||
"""
|
||||
return self._distribution_system
|
||||
|
||||
@distribution_system.setter
|
||||
def distribution_system(self, value):
|
||||
"""
|
||||
Set distribution system
|
||||
:param value: DistributionSystem
|
||||
"""
|
||||
self._distribution_system = value
|
||||
|
||||
@property
|
||||
def emission_system(self) -> Union[None, EmissionSystem]:
|
||||
"""
|
||||
Get emission system
|
||||
:return: EmissionSystem
|
||||
"""
|
||||
return self._emission_system
|
||||
|
||||
@emission_system.setter
|
||||
def emission_system(self, value):
|
||||
"""
|
||||
Set emission system
|
||||
:param value: EmissionSystem
|
||||
"""
|
||||
self._emission_system = value
|
||||
|
||||
@property
|
||||
def connected_city_objects(self) -> Union[None, List[CityObject]]:
|
||||
"""
|
||||
Get list of city objects that are connected to this energy system
|
||||
:return: List[CityObject]
|
||||
"""
|
||||
return self._connected_city_objects
|
||||
|
||||
@connected_city_objects.setter
|
||||
def connected_city_objects(self, value):
|
||||
"""
|
||||
Set list of city objects that are connected to this energy system
|
||||
:param value: List[CityObject]
|
||||
"""
|
||||
self._connected_city_objects = value
|
||||
|
||||
@property
|
||||
def control_system(self) -> Union[None, ControlSystem]:
|
||||
"""
|
||||
Get control system of the energy system
|
||||
:return: ControlSystem
|
||||
"""
|
||||
return self._control_system
|
||||
|
||||
@control_system.setter
|
||||
def control_system(self, value):
|
||||
"""
|
||||
Set control system of the energy system
|
||||
:param value: ControlSystem
|
||||
"""
|
||||
self._control_system = value
|
120
hub/city_model_structure/energy_systems/generation_system.py
Normal file
120
hub/city_model_structure/energy_systems/generation_system.py
Normal file
|
@ -0,0 +1,120 @@
|
|||
"""
|
||||
Energy generation system definition
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2023 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
from typing import Union
|
||||
|
||||
from hub.city_model_structure.energy_systems.generic_generation_system import GenericGenerationSystem
|
||||
|
||||
|
||||
class GenerationSystem:
|
||||
"""
|
||||
GenerationSystem class
|
||||
"""
|
||||
def __init__(self):
|
||||
self._heat_power = None
|
||||
self._cooling_power = None
|
||||
self._electricity_power = None
|
||||
self._storage_capacity = None
|
||||
self._generic_generation_system = None
|
||||
self._auxiliary_equipment = None
|
||||
|
||||
@property
|
||||
def generic_generation_system(self) -> GenericGenerationSystem:
|
||||
"""
|
||||
Get associated generic_generation_system
|
||||
:return: GenericGenerationSystem
|
||||
"""
|
||||
return self._generic_generation_system
|
||||
|
||||
@generic_generation_system.setter
|
||||
def generic_generation_system(self, value):
|
||||
"""
|
||||
Set associated generic_generation_system
|
||||
:param value: GenericGenerationSystem
|
||||
"""
|
||||
self._generic_generation_system = value
|
||||
|
||||
@property
|
||||
def heat_power(self):
|
||||
"""
|
||||
Get heat_power in W
|
||||
:return: float
|
||||
"""
|
||||
return self._heat_power
|
||||
|
||||
@heat_power.setter
|
||||
def heat_power(self, value):
|
||||
"""
|
||||
Set heat_power in W
|
||||
:param value: float
|
||||
"""
|
||||
self._heat_power = value
|
||||
|
||||
@property
|
||||
def cooling_power(self):
|
||||
"""
|
||||
Get cooling_power in W
|
||||
:return: float
|
||||
"""
|
||||
return self._cooling_power
|
||||
|
||||
@cooling_power.setter
|
||||
def cooling_power(self, value):
|
||||
"""
|
||||
Set cooling_power in W
|
||||
:param value: float
|
||||
"""
|
||||
self._cooling_power = value
|
||||
|
||||
@property
|
||||
def electricity_power(self):
|
||||
"""
|
||||
Get electricity_power in W
|
||||
:return: float
|
||||
"""
|
||||
return self._electricity_power
|
||||
|
||||
@electricity_power.setter
|
||||
def electricity_power(self, value):
|
||||
"""
|
||||
Set electricity_power in W
|
||||
:param value: float
|
||||
"""
|
||||
self._electricity_power = value
|
||||
|
||||
@property
|
||||
def storage_capacity(self):
|
||||
"""
|
||||
Get storage_capacity in J
|
||||
:return: float
|
||||
"""
|
||||
return self._storage_capacity
|
||||
|
||||
@storage_capacity.setter
|
||||
def storage_capacity(self, value):
|
||||
"""
|
||||
Set storage_capacity in J
|
||||
:param value: float
|
||||
"""
|
||||
self._storage_capacity = value
|
||||
|
||||
@property
|
||||
def auxiliary_equipment(self) -> Union[None, GenerationSystem]:
|
||||
"""
|
||||
Get auxiliary_equipment
|
||||
:return: GenerationSystem
|
||||
"""
|
||||
return self._auxiliary_equipment
|
||||
|
||||
@auxiliary_equipment.setter
|
||||
def auxiliary_equipment(self, value):
|
||||
"""
|
||||
Set auxiliary_equipment
|
||||
:param value: GenerationSystem
|
||||
"""
|
||||
self._auxiliary_equipment = value
|
|
@ -0,0 +1,81 @@
|
|||
"""
|
||||
Generic energy distribution system definition
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2023 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
|
||||
class GenericDistributionSystem:
|
||||
"""
|
||||
GenericDistributionSystem class
|
||||
"""
|
||||
def __init__(self):
|
||||
self._type = None
|
||||
self._supply_temperature = None
|
||||
self._distribution_consumption = None
|
||||
self._heat_losses = None
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
"""
|
||||
Get type from [air, water, refrigerant]
|
||||
:return: string
|
||||
"""
|
||||
return self._type
|
||||
|
||||
@type.setter
|
||||
def type(self, value):
|
||||
"""
|
||||
Set type from [air, water, refrigerant]
|
||||
:param value: string
|
||||
"""
|
||||
self._type = value
|
||||
|
||||
@property
|
||||
def supply_temperature(self):
|
||||
"""
|
||||
Get supply_temperature in degree Celsius
|
||||
:return: float
|
||||
"""
|
||||
return self._supply_temperature
|
||||
|
||||
@supply_temperature.setter
|
||||
def supply_temperature(self, value):
|
||||
"""
|
||||
Set supply_temperature in degree Celsius
|
||||
:param value: float
|
||||
"""
|
||||
self._supply_temperature = value
|
||||
|
||||
@property
|
||||
def distribution_consumption(self):
|
||||
"""
|
||||
Get distribution_consumption (pump of fan) in ratio over energy produced
|
||||
:return: float
|
||||
"""
|
||||
return self._distribution_consumption
|
||||
|
||||
@distribution_consumption.setter
|
||||
def distribution_consumption(self, value):
|
||||
"""
|
||||
Set distribution_consumption (pump of fan) in ratio over energy produced
|
||||
:param value: float
|
||||
"""
|
||||
self._distribution_consumption = value
|
||||
|
||||
@property
|
||||
def heat_losses(self):
|
||||
"""
|
||||
Get heat_losses in ratio over energy produced
|
||||
:return: float
|
||||
"""
|
||||
return self._heat_losses
|
||||
|
||||
@heat_losses.setter
|
||||
def heat_losses(self, value):
|
||||
"""
|
||||
Set heat_losses in ratio over energy produced
|
||||
:param value: float
|
||||
"""
|
||||
self._heat_losses = value
|
|
@ -0,0 +1,30 @@
|
|||
"""
|
||||
Generic energy emission system definition
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2023 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
|
||||
class GenericEmissionSystem:
|
||||
"""
|
||||
GenericEmissionSystem class
|
||||
"""
|
||||
def __init__(self):
|
||||
self._parasitic_energy_consumption = None
|
||||
|
||||
@property
|
||||
def parasitic_energy_consumption(self):
|
||||
"""
|
||||
Get parasitic_energy_consumption in ratio (W/W)
|
||||
:return: float
|
||||
"""
|
||||
return self._parasitic_energy_consumption
|
||||
|
||||
@parasitic_energy_consumption.setter
|
||||
def parasitic_energy_consumption(self, value):
|
||||
"""
|
||||
Set parasitic_energy_consumption in ratio (W/W)
|
||||
:param value: float
|
||||
"""
|
||||
self._parasitic_energy_consumption = value
|
106
hub/city_model_structure/energy_systems/generic_energy_system.py
Normal file
106
hub/city_model_structure/energy_systems/generic_energy_system.py
Normal file
|
@ -0,0 +1,106 @@
|
|||
"""
|
||||
Generic energy system definition
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2023 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
from typing import Union, List
|
||||
|
||||
from hub.city_model_structure.energy_systems.generic_generation_system import GenericGenerationSystem
|
||||
from hub.city_model_structure.energy_systems.generic_distribution_system import GenericDistributionSystem
|
||||
from hub.city_model_structure.energy_systems.generic_emission_system import GenericEmissionSystem
|
||||
from hub.city_model_structure.city_object import CityObject
|
||||
|
||||
|
||||
class GenericEnergySystem:
|
||||
"""
|
||||
GenericEnergySystem class
|
||||
"""
|
||||
def __init__(self):
|
||||
self._name = None
|
||||
self._demand_types = None
|
||||
self._generation_system = None
|
||||
self._distribution_system = None
|
||||
self._emission_system = None
|
||||
self._connected_city_objects = None
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""
|
||||
Get energy system name
|
||||
:return: str
|
||||
"""
|
||||
return self._name
|
||||
|
||||
@name.setter
|
||||
def name(self, value):
|
||||
"""
|
||||
Set energy system name
|
||||
:param value:
|
||||
"""
|
||||
self._name = value
|
||||
|
||||
@property
|
||||
def demand_types(self):
|
||||
"""
|
||||
Get demand able to cover from [Heating, Cooling, Domestic Hot Water, Electricity]
|
||||
:return: [string]
|
||||
"""
|
||||
return self._demand_types
|
||||
|
||||
@demand_types.setter
|
||||
def demand_types(self, value):
|
||||
"""
|
||||
Set demand able to cover from [Heating, Cooling, Domestic Hot Water, Electricity]
|
||||
:param value: [string]
|
||||
"""
|
||||
self._demand_types = value
|
||||
|
||||
@property
|
||||
def generation_system(self) -> GenericGenerationSystem:
|
||||
"""
|
||||
Get generation system
|
||||
:return: GenerationSystem
|
||||
"""
|
||||
return self._generation_system
|
||||
|
||||
@generation_system.setter
|
||||
def generation_system(self, value):
|
||||
"""
|
||||
Set generation system
|
||||
:return: GenerationSystem
|
||||
"""
|
||||
self._generation_system = value
|
||||
|
||||
@property
|
||||
def distribution_system(self) -> Union[None, GenericDistributionSystem]:
|
||||
"""
|
||||
Get distribution system
|
||||
:return: DistributionSystem
|
||||
"""
|
||||
return self._distribution_system
|
||||
|
||||
@distribution_system.setter
|
||||
def distribution_system(self, value):
|
||||
"""
|
||||
Set distribution system
|
||||
:param value: DistributionSystem
|
||||
"""
|
||||
self._distribution_system = value
|
||||
|
||||
@property
|
||||
def emission_system(self) -> Union[None, GenericEmissionSystem]:
|
||||
"""
|
||||
Get emission system
|
||||
:return: EmissionSystem
|
||||
"""
|
||||
return self._emission_system
|
||||
|
||||
@emission_system.setter
|
||||
def emission_system(self, value):
|
||||
"""
|
||||
Set emission system
|
||||
:param value: EmissionSystem
|
||||
"""
|
||||
self._emission_system = value
|
|
@ -0,0 +1,186 @@
|
|||
"""
|
||||
Generic energy generation system definition
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2023 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
from typing import Union
|
||||
|
||||
|
||||
class GenericGenerationSystem:
|
||||
"""
|
||||
GenericGenerationSystem class
|
||||
"""
|
||||
def __init__(self):
|
||||
self._type = None
|
||||
self._fuel_type = None
|
||||
self._source_types = None
|
||||
self._heat_efficiency = None
|
||||
self._cooling_efficiency = None
|
||||
self._electricity_efficiency = None
|
||||
self._source_temperature = None
|
||||
self._source_mass_flow = None
|
||||
self._storage = None
|
||||
self._auxiliary_equipment = None
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
"""
|
||||
Get system type
|
||||
:return: string
|
||||
"""
|
||||
return self._type
|
||||
|
||||
@type.setter
|
||||
def type(self, value):
|
||||
"""
|
||||
Set system type
|
||||
:param value: string
|
||||
"""
|
||||
self._type = value
|
||||
|
||||
@property
|
||||
def fuel_type(self):
|
||||
"""
|
||||
Get fuel_type from [Renewable, Gas, Diesel, Electricity, Wood, Coal]
|
||||
:return: string
|
||||
"""
|
||||
return self._fuel_type
|
||||
|
||||
@fuel_type.setter
|
||||
def fuel_type(self, value):
|
||||
"""
|
||||
Set fuel_type from [Renewable, Gas, Diesel, Electricity, Wood, Coal]
|
||||
:param value: string
|
||||
"""
|
||||
self._fuel_type = value
|
||||
|
||||
@property
|
||||
def source_types(self):
|
||||
"""
|
||||
Get source_type from [Air, Water, Geothermal, District Heating, Grid, Onsite Electricity]
|
||||
:return: [string]
|
||||
"""
|
||||
return self._source_types
|
||||
|
||||
@source_types.setter
|
||||
def source_types(self, value):
|
||||
"""
|
||||
Set source_type from [Air, Water, Geothermal, District Heating, Grid, Onsite Electricity]
|
||||
:param value: [string]
|
||||
"""
|
||||
self._source_types = value
|
||||
|
||||
@property
|
||||
def heat_efficiency(self):
|
||||
"""
|
||||
Get heat_efficiency
|
||||
:return: float
|
||||
"""
|
||||
return self._heat_efficiency
|
||||
|
||||
@heat_efficiency.setter
|
||||
def heat_efficiency(self, value):
|
||||
"""
|
||||
Set heat_efficiency
|
||||
:param value: float
|
||||
"""
|
||||
self._heat_efficiency = value
|
||||
|
||||
@property
|
||||
def cooling_efficiency(self):
|
||||
"""
|
||||
Get cooling_efficiency
|
||||
:return: float
|
||||
"""
|
||||
return self._cooling_efficiency
|
||||
|
||||
@cooling_efficiency.setter
|
||||
def cooling_efficiency(self, value):
|
||||
"""
|
||||
Set cooling_efficiency
|
||||
:param value: float
|
||||
"""
|
||||
self._cooling_efficiency = value
|
||||
|
||||
@property
|
||||
def electricity_efficiency(self):
|
||||
"""
|
||||
Get electricity_efficiency
|
||||
:return: float
|
||||
"""
|
||||
return self._electricity_efficiency
|
||||
|
||||
@electricity_efficiency.setter
|
||||
def electricity_efficiency(self, value):
|
||||
"""
|
||||
Set electricity_efficiency
|
||||
:param value: float
|
||||
"""
|
||||
self._electricity_efficiency = value
|
||||
|
||||
@property
|
||||
def source_temperature(self):
|
||||
"""
|
||||
Get source_temperature in degree Celsius
|
||||
:return: float
|
||||
"""
|
||||
return self._source_temperature
|
||||
|
||||
@source_temperature.setter
|
||||
def source_temperature(self, value):
|
||||
"""
|
||||
Set source_temperature in degree Celsius
|
||||
:param value: float
|
||||
"""
|
||||
self._source_temperature = value
|
||||
|
||||
@property
|
||||
def source_mass_flow(self):
|
||||
"""
|
||||
Get source_mass_flow in kg/s
|
||||
:return: float
|
||||
"""
|
||||
return self._source_mass_flow
|
||||
|
||||
@source_mass_flow.setter
|
||||
def source_mass_flow(self, value):
|
||||
"""
|
||||
Set source_mass_flow in kg/s
|
||||
:param value: float
|
||||
"""
|
||||
self._source_mass_flow = value
|
||||
|
||||
@property
|
||||
def storage(self):
|
||||
"""
|
||||
Get boolean storage exists
|
||||
:return: bool
|
||||
"""
|
||||
return self._storage
|
||||
|
||||
@storage.setter
|
||||
def storage(self, value):
|
||||
"""
|
||||
Set boolean storage exists
|
||||
:return: bool
|
||||
"""
|
||||
self._storage = value
|
||||
|
||||
@property
|
||||
def auxiliary_equipment(self) -> Union[None, GenericGenerationSystem]:
|
||||
"""
|
||||
Get auxiliary_equipment
|
||||
:return: GenerationSystem
|
||||
"""
|
||||
return self._auxiliary_equipment
|
||||
|
||||
@auxiliary_equipment.setter
|
||||
def auxiliary_equipment(self, value):
|
||||
"""
|
||||
Set auxiliary_equipment
|
||||
:return: GenerationSystem
|
||||
"""
|
||||
self._auxiliary_equipment = value
|
|
@ -16,6 +16,7 @@ class LevelOfDetail:
|
|||
self._usage = None
|
||||
self._weather = None
|
||||
self._surface_radiation = None
|
||||
self._energy_systems = None
|
||||
|
||||
@property
|
||||
def geometry(self):
|
||||
|
@ -75,7 +76,7 @@ class LevelOfDetail:
|
|||
"""
|
||||
Set the city minimal weather level of detail, 0 (yearly), 1 (monthly), 2 (hourly)
|
||||
"""
|
||||
self._usage = value
|
||||
self._weather = value
|
||||
|
||||
@property
|
||||
def surface_radiation(self):
|
||||
|
@ -91,3 +92,18 @@ class LevelOfDetail:
|
|||
Set the city minimal surface radiation level of detail, 0 (yearly), 1 (monthly), 2 (hourly)
|
||||
"""
|
||||
self._surface_radiation = value
|
||||
|
||||
@property
|
||||
def energy_systems(self):
|
||||
"""
|
||||
Get the city minimal energy systems level of detail, 1 or 2
|
||||
:return: int
|
||||
"""
|
||||
return self._energy_systems
|
||||
|
||||
@energy_systems.setter
|
||||
def energy_systems(self, value):
|
||||
"""
|
||||
Set the city minimal energy systems level of detail, 1 or 2
|
||||
"""
|
||||
self._energy_systems = value
|
||||
|
|
225
hub/data/energy_systems/montreal_custom_systems.xml
Normal file
225
hub/data/energy_systems/montreal_custom_systems.xml
Normal file
|
@ -0,0 +1,225 @@
|
|||
<catalog lod="1">
|
||||
<equipments>
|
||||
<equipment id="1" type="boiler" fuel_type="gas">
|
||||
<name>Fuel-fired water boiler with baseboards</name>
|
||||
<demands>
|
||||
<demand>heating</demand>
|
||||
<demand>domestic_hot_water</demand>
|
||||
</demands>
|
||||
<heating_efficiency>0.85</heating_efficiency>
|
||||
<distribution_heat_losses units="%">10</distribution_heat_losses>
|
||||
<distribution_consumption units="%">2</distribution_consumption>
|
||||
<storage>false</storage>
|
||||
</equipment>
|
||||
<equipment id="2" type="boiler" fuel_type="electricity">
|
||||
<name>Electrical resistance water boiler</name>
|
||||
<demands>
|
||||
<demand>heating</demand>
|
||||
<demand>domestic_hot_water</demand>
|
||||
</demands>
|
||||
<heating_efficiency>1</heating_efficiency>
|
||||
<distribution_heat_losses units="%">10</distribution_heat_losses>
|
||||
<distribution_consumption units="%">2</distribution_consumption>
|
||||
<storage>true</storage>
|
||||
</equipment>
|
||||
<equipment id="3" type="furnace" fuel_type="gas">
|
||||
<name>Fuel-fired furnace and fuel boiler for acs</name>
|
||||
<demands>
|
||||
<demand>heating</demand>
|
||||
<demand>domestic_hot_water</demand>
|
||||
</demands>
|
||||
<heating_efficiency>0.85</heating_efficiency>
|
||||
<distribution_heat_losses units="%">25</distribution_heat_losses>
|
||||
<distribution_consumption units="%">100000</distribution_consumption>
|
||||
<storage>false</storage>
|
||||
</equipment>
|
||||
<equipment id="4" type="furnace" fuel_type="electricity">
|
||||
<name>Electrical resistance furnace and electrical boiler for acs</name>
|
||||
<demands>
|
||||
<demand>heating</demand>
|
||||
<demand>domestic_hot_water</demand>
|
||||
</demands>
|
||||
<heating_efficiency>1</heating_efficiency>
|
||||
<distribution_heat_losses units="%">25</distribution_heat_losses>
|
||||
<distribution_consumption units="%">100000</distribution_consumption>
|
||||
<storage>false</storage>
|
||||
</equipment>
|
||||
<equipment id="5" type="baseboard" fuel_type="gas">
|
||||
<name>Baseboards: hydronic with fuel boiler</name>
|
||||
<demands>
|
||||
<demand>heating</demand>
|
||||
<demand>domestic_hot_water</demand>
|
||||
</demands>
|
||||
<heating_efficiency>0.85</heating_efficiency>
|
||||
<distribution_heat_losses units="%">10</distribution_heat_losses>
|
||||
<distribution_consumption units="%">2</distribution_consumption>
|
||||
<storage>false</storage>
|
||||
</equipment>
|
||||
<equipment id="6" type="baseboard" fuel_type="electricity">
|
||||
<name>Electrical baseboards and electrical boiler for acs</name>
|
||||
<demands>
|
||||
<demand>heating</demand>
|
||||
<demand>domestic_hot_water</demand>
|
||||
</demands>
|
||||
<heating_efficiency>1</heating_efficiency>
|
||||
<distribution_heat_losses units="%">0</distribution_heat_losses>
|
||||
<distribution_consumption units="%">0</distribution_consumption>
|
||||
<storage>false</storage>
|
||||
</equipment>
|
||||
<equipment id="7" type="cooler" fuel_type="electricity">
|
||||
<name>Air cooled DX with external condenser</name>
|
||||
<demands>
|
||||
<demand>cooling</demand>
|
||||
</demands>
|
||||
<cooling_efficiency>3.23</cooling_efficiency>
|
||||
<distribution_heat_losses units="%">0</distribution_heat_losses>
|
||||
<distribution_consumption units="%">100000</distribution_consumption>
|
||||
<storage>false</storage>
|
||||
</equipment>
|
||||
<equipment id="8" type="cooler" fuel_type="electricity">
|
||||
<name>Water cooled, water chiller</name>
|
||||
<demands>
|
||||
<demand>cooling</demand>
|
||||
</demands>
|
||||
<cooling_efficiency>3.23</cooling_efficiency>
|
||||
<distribution_heat_losses units="%">10</distribution_heat_losses>
|
||||
<distribution_consumption units="%">5</distribution_consumption>
|
||||
<storage>false</storage>
|
||||
</equipment>
|
||||
<equipment id="9" type="cooler" fuel_type="electricity">
|
||||
<name>Air cooled DX</name>
|
||||
<demands>
|
||||
<demand>cooling</demand>
|
||||
</demands>
|
||||
<cooling_efficiency>3.23</cooling_efficiency>
|
||||
<distribution_heat_losses units="%">0</distribution_heat_losses>
|
||||
<distribution_consumption units="%">100000</distribution_consumption>
|
||||
<storage>false</storage>
|
||||
</equipment>
|
||||
<equipment id="10" type="electricity generator" fuel_type="renewable">
|
||||
<name>PV system</name>
|
||||
<demands>
|
||||
<demand>electricity</demand>
|
||||
</demands>
|
||||
<electrical_efficiency>0.22</electrical_efficiency>
|
||||
<storage>true</storage>
|
||||
</equipment>
|
||||
</equipments>
|
||||
<systems>
|
||||
<system name="system 1 gas">
|
||||
<equipments>
|
||||
<equipment_id>1</equipment_id>
|
||||
<equipment_id>7</equipment_id>
|
||||
</equipments>
|
||||
</system>
|
||||
<system name="system 1 gas pv">
|
||||
<equipments>
|
||||
<equipment_id>1</equipment_id>
|
||||
<equipment_id>7</equipment_id>
|
||||
<equipment_id>10</equipment_id>
|
||||
</equipments>
|
||||
</system>
|
||||
<system name="system 1 electricity">
|
||||
<equipments>
|
||||
<equipment_id>2</equipment_id>
|
||||
<equipment_id>7</equipment_id>
|
||||
</equipments>
|
||||
</system>
|
||||
<system name="system 1 electricity pv">
|
||||
<equipments>
|
||||
<equipment_id>2</equipment_id>
|
||||
<equipment_id>7</equipment_id>
|
||||
<equipment_id>10</equipment_id>
|
||||
</equipments>
|
||||
</system>
|
||||
<system name="system 2 gas">
|
||||
<equipments>
|
||||
<equipment_id>1</equipment_id>
|
||||
<equipment_id>8</equipment_id>
|
||||
</equipments>
|
||||
</system>
|
||||
<system name="system 2 gas pv">
|
||||
<equipments>
|
||||
<equipment_id>1</equipment_id>
|
||||
<equipment_id>8</equipment_id>
|
||||
<equipment_id>10</equipment_id>
|
||||
</equipments>
|
||||
</system>
|
||||
<system name="system 2 electricity">
|
||||
<equipments>
|
||||
<equipment_id>2</equipment_id>
|
||||
<equipment_id>8</equipment_id>
|
||||
</equipments>
|
||||
</system>
|
||||
<system name="system 2 electricity pv">
|
||||
<equipments>
|
||||
<equipment_id>2</equipment_id>
|
||||
<equipment_id>8</equipment_id>
|
||||
<equipment_id>10</equipment_id>
|
||||
</equipments>
|
||||
</system>
|
||||
<system name="system 3 and 4 gas">
|
||||
<equipments>
|
||||
<equipment_id>3</equipment_id>
|
||||
<equipment_id>4</equipment_id>
|
||||
</equipments>
|
||||
</system>
|
||||
<system name="system 3 and 4 gas pv">
|
||||
<equipments>
|
||||
<equipment_id>3</equipment_id>
|
||||
<equipment_id>4</equipment_id>
|
||||
<equipment_id>10</equipment_id>
|
||||
</equipments>
|
||||
</system>
|
||||
<system name="system 3 and 4 electricity">
|
||||
<equipments>
|
||||
<equipment_id>4</equipment_id>
|
||||
<equipment_id>4</equipment_id>
|
||||
</equipments>
|
||||
</system>
|
||||
<system name="system 3 and 4 electricity pv">
|
||||
<equipments>
|
||||
<equipment_id>4</equipment_id>
|
||||
<equipment_id>4</equipment_id>
|
||||
<equipment_id>10</equipment_id>
|
||||
</equipments>
|
||||
</system>
|
||||
<system name="system 5">
|
||||
<equipments>
|
||||
<equipment_id>8</equipment_id>
|
||||
</equipments>
|
||||
</system>
|
||||
<system name="system 5 pv">
|
||||
<equipments>
|
||||
<equipment_id>8</equipment_id>
|
||||
<equipment_id>10</equipment_id>
|
||||
</equipments>
|
||||
</system>
|
||||
<system name="system 6 gas">
|
||||
<equipments>
|
||||
<equipment_id>5</equipment_id>
|
||||
<equipment_id>8</equipment_id>
|
||||
</equipments>
|
||||
</system>
|
||||
<system name="system 6 gas pv">
|
||||
<equipments>
|
||||
<equipment_id>5</equipment_id>
|
||||
<equipment_id>8</equipment_id>
|
||||
<equipment_id>10</equipment_id>
|
||||
</equipments>
|
||||
</system>
|
||||
<system name="system 6 electricity">
|
||||
<equipments>
|
||||
<equipment_id>6</equipment_id>
|
||||
<equipment_id>8</equipment_id>
|
||||
</equipments>
|
||||
</system>
|
||||
<system name="system 6 electricity pv">
|
||||
<equipments>
|
||||
<equipment_id>6</equipment_id>
|
||||
<equipment_id>8</equipment_id>
|
||||
<equipment_id>10</equipment_id>
|
||||
</equipments>
|
||||
</system>
|
||||
</systems>
|
||||
</catalog>
|
|
@ -1,11 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<nrcan base_url="https://raw.githubusercontent.com/NREL/openstudio-standards/master/lib/openstudio-standards/standards/necb/ECMS/data/">
|
||||
<boilers_location>boiler_set.json</boilers_location>
|
||||
<chillers_location>chiller_set.json</chillers_location>
|
||||
<curves_location>curves.json</curves_location>
|
||||
<furnaces_location>furnace_set.json </furnaces_location>
|
||||
<heat_pumps_location>heat_pumps.json</heat_pumps_location>
|
||||
<domestic_hot_water_systems_location>shw_set.json</domestic_hot_water_systems_location>
|
||||
<pvs_location>pv.json</pvs_location>
|
||||
<air_conditioners_location>unitary_acs.json</air_conditioners_location>
|
||||
</nrcan>
|
|
@ -51,7 +51,6 @@ class InselMonthlyEnergyBalance(Insel):
|
|||
)
|
||||
self._export()
|
||||
|
||||
|
||||
def _export(self):
|
||||
for i_file, content in enumerate(self._contents):
|
||||
file_name = self._insel_files_paths[i_file]
|
||||
|
@ -63,7 +62,7 @@ class InselMonthlyEnergyBalance(Insel):
|
|||
levels_of_detail = self._city.level_of_detail
|
||||
if levels_of_detail.geometry is None:
|
||||
raise Exception(f'Level of detail of geometry not assigned')
|
||||
if levels_of_detail.geometry < 0.5:
|
||||
if levels_of_detail.geometry < 1:
|
||||
raise Exception(f'Level of detail of geometry = {levels_of_detail.geometry}. Required minimum level 0.5')
|
||||
if levels_of_detail.construction is None:
|
||||
raise Exception(f'Level of detail of construction not assigned')
|
||||
|
@ -73,13 +72,15 @@ class InselMonthlyEnergyBalance(Insel):
|
|||
raise Exception(f'Level of detail of usage not assigned')
|
||||
if levels_of_detail.usage < 1:
|
||||
raise Exception(f'Level of detail of usage = {levels_of_detail.usage}. Required minimum level 1')
|
||||
for building in self._city.buildings:
|
||||
if cte.MONTH not in building.external_temperature:
|
||||
raise Exception(f'Building {building.name} does not have external temperature assigned')
|
||||
for surface in building.surfaces:
|
||||
if surface.type != cte.GROUND:
|
||||
if cte.MONTH not in surface.global_irradiance:
|
||||
raise Exception(f'Building {building.name} does not have global irradiance on surfaces assigned')
|
||||
if levels_of_detail.weather is None:
|
||||
raise Exception(f'Level of detail of usage not assigned')
|
||||
if levels_of_detail.weather < 1:
|
||||
raise Exception(f'Level of detail of weather = {levels_of_detail.weather}. Required minimum level 1')
|
||||
if levels_of_detail.surface_radiation is None:
|
||||
raise Exception(f'Level of detail of usage not assigned')
|
||||
if levels_of_detail.surface_radiation < 1:
|
||||
raise Exception(f'Level of detail of surface radiation = {levels_of_detail.surface_radiation}. '
|
||||
f'Required minimum level 1')
|
||||
|
||||
@staticmethod
|
||||
def _generate_meb_template(building, insel_outputs_path, radiation_calculation_method, weather_format):
|
||||
|
|
|
@ -164,6 +164,23 @@ EQUIPMENT = 'Equipment'
|
|||
ACTIVITY = 'Activity'
|
||||
PEOPLE_ACTIVITY_LEVEL = 'People Activity Level'
|
||||
DOMESTIC_HOT_WATER = 'Domestic Hot Water'
|
||||
HEATING = 'Heating'
|
||||
COOLING = 'Cooling'
|
||||
ELECTRICITY = 'Electricity'
|
||||
RENEWABLE = 'Renewable'
|
||||
WOOD = 'Wood'
|
||||
GAS = 'Gas'
|
||||
DIESEL = 'Diesel'
|
||||
COAL = 'Coal'
|
||||
AIR = 'Air'
|
||||
WATER = 'Water'
|
||||
GEOTHERMAL = 'Geothermal'
|
||||
DISTRICT_HEATING_NETWORK = 'District Heating'
|
||||
GRID = 'Grid'
|
||||
ONSITE_ELECTRICITY = 'Onsite Electricity'
|
||||
PHOTOVOLTAIC = 'Photovoltaic'
|
||||
BOILER = 'Boiler'
|
||||
HEAT_PUMP = 'Heat Pump'
|
||||
|
||||
# Geometry
|
||||
EPSILON = 0.0000001
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
"""
|
||||
Dictionaries module for Montreal system catalog demand types to hub energy demand types
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2023 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
import hub.helpers.constants as cte
|
||||
|
||||
|
||||
class MontrealDemandTypeToHubEnergyDemandType:
|
||||
|
||||
def __init__(self):
|
||||
self._dictionary = {'heating': cte.HEATING,
|
||||
'cooling': cte.COOLING,
|
||||
'domestic_hot_water': cte.DOMESTIC_HOT_WATER,
|
||||
'electricity': cte.ELECTRICITY,
|
||||
}
|
||||
|
||||
@property
|
||||
def dictionary(self) -> dict:
|
||||
return self._dictionary
|
|
@ -0,0 +1,26 @@
|
|||
"""
|
||||
Dictionaries module for Montreal system to hub energy generation system
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2023 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@property
|
||||
def dictionary(self) -> dict:
|
||||
return self._dictionary
|
|
@ -14,6 +14,8 @@ from hub.helpers.data.hub_function_to_nrcan_construction_function import HubFunc
|
|||
from hub.helpers.data.hub_usage_to_comnet_usage import HubUsageToComnetUsage
|
||||
from hub.helpers.data.hub_usage_to_hft_usage import HubUsageToHftUsage
|
||||
from hub.helpers.data.hub_usage_to_nrcan_usage import HubUsageToNrcanUsage
|
||||
from hub.helpers.data.montreal_system_to_hub_energy_generation_system import MontrealSystemToHubEnergyGenerationSystem
|
||||
from hub.helpers.data.montreal_demand_type_to_hub_energy_demand_type import MontrealDemandTypeToHubEnergyDemandType
|
||||
from hub.helpers.data.hub_function_to_montreal_custom_costs_function import HubFunctionToMontrealCustomCostsFunction
|
||||
|
||||
|
||||
|
@ -92,6 +94,20 @@ class Dictionaries:
|
|||
"""
|
||||
return AlkisFunctionToHubFunction().dictionary
|
||||
|
||||
@property
|
||||
def montreal_system_to_hub_energy_generation_system(self):
|
||||
"""
|
||||
Get montreal custom system names to hub energy system names, transformation dictionary
|
||||
"""
|
||||
return MontrealSystemToHubEnergyGenerationSystem().dictionary
|
||||
|
||||
@property
|
||||
def montreal_demand_type_to_hub_energy_demand_type(self):
|
||||
"""
|
||||
Get montreal custom system demand type to hub energy demand type, transformation dictionary
|
||||
"""
|
||||
return MontrealDemandTypeToHubEnergyDemandType().dictionary
|
||||
|
||||
@property
|
||||
def hub_function_to_montreal_custom_costs_function(self) -> dict:
|
||||
"""
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
"""
|
||||
Cooling and Heating peak loads module
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2023 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
Code contributors: Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||
"""
|
||||
|
||||
import math
|
||||
|
||||
import hub.helpers.constants as cte
|
||||
|
@ -5,67 +13,107 @@ from hub.helpers.peak_calculation.loads_calculation import LoadsCalculation
|
|||
|
||||
_MONTH_STARTING_HOUR = [0, 744, 1416, 2160, 2880, 3624, 4344, 5088, 5832, 6552, 7296, 8016, math.inf]
|
||||
|
||||
def peak_loads_from_hourly(hourly_values):
|
||||
month = 1
|
||||
peaks = [0 for _ in range(12)]
|
||||
for i, value in enumerate(hourly_values):
|
||||
if _MONTH_STARTING_HOUR[month] <= i:
|
||||
month += 1
|
||||
if value > peaks[month-1]:
|
||||
peaks[month-1] = value
|
||||
return peaks
|
||||
|
||||
def heating_peak_loads_from_methodology(building):
|
||||
monthly_heating_loads = []
|
||||
ambient_temperature = building.external_temperature[cte.HOUR]['epw']
|
||||
for month in range(0, 12):
|
||||
ground_temperature = building.ground_temperature[cte.MONTH]['2'][month]
|
||||
heating_ambient_temperature = 100
|
||||
start_hour = _MONTH_STARTING_HOUR[month]
|
||||
end_hour = 8760
|
||||
if month < 11:
|
||||
end_hour = _MONTH_STARTING_HOUR[month + 1]
|
||||
for hour in range(start_hour, end_hour):
|
||||
temperature = ambient_temperature[hour]
|
||||
if temperature < heating_ambient_temperature:
|
||||
heating_ambient_temperature = temperature
|
||||
loads = LoadsCalculation(building)
|
||||
heating_load_transmitted = loads.get_heating_transmitted_load(heating_ambient_temperature, ground_temperature)
|
||||
heating_load_ventilation_sensible = loads.get_heating_ventilation_load_sensible(heating_ambient_temperature)
|
||||
heating_load_ventilation_latent = 0
|
||||
heating_load = heating_load_transmitted + heating_load_ventilation_sensible + heating_load_ventilation_latent
|
||||
if heating_load < 0:
|
||||
heating_load = 0
|
||||
monthly_heating_loads.append(heating_load)
|
||||
return monthly_heating_loads
|
||||
class PeakLoads:
|
||||
"""
|
||||
PeakLoads class
|
||||
"""
|
||||
def __init__(self, building=None):
|
||||
self._building = building
|
||||
|
||||
def cooling_peak_loads_from_methodology(building):
|
||||
monthly_cooling_loads = []
|
||||
ambient_temperature = building.external_temperature[cte.HOUR]['epw']
|
||||
for month in range(0, 12):
|
||||
ground_temperature = building.ground_temperature[cte.MONTH]['2'][month]
|
||||
cooling_ambient_temperature = -100
|
||||
cooling_calculation_hour = -1
|
||||
start_hour = _MONTH_STARTING_HOUR[month]
|
||||
end_hour = 8760
|
||||
if month < 11:
|
||||
end_hour = _MONTH_STARTING_HOUR[month + 1]
|
||||
for hour in range(start_hour, end_hour):
|
||||
temperature = ambient_temperature[hour]
|
||||
if temperature > cooling_ambient_temperature:
|
||||
cooling_ambient_temperature = temperature
|
||||
cooling_calculation_hour = hour
|
||||
loads = LoadsCalculation(building)
|
||||
cooling_load_transmitted = loads.get_cooling_transmitted_load(cooling_ambient_temperature, ground_temperature)
|
||||
cooling_load_renovation_sensible = loads.get_cooling_ventilation_load_sensible(cooling_ambient_temperature)
|
||||
cooling_load_internal_gains_sensible = loads.get_internal_load_sensible()
|
||||
cooling_load_radiation = loads.get_radiation_load('sra', cooling_calculation_hour)
|
||||
cooling_load_sensible = cooling_load_transmitted + cooling_load_renovation_sensible - cooling_load_radiation \
|
||||
- cooling_load_internal_gains_sensible
|
||||
def _can_be_calculated(self):
|
||||
levels_of_detail = self._building.level_of_detail
|
||||
can_be_calculated = True
|
||||
if levels_of_detail.geometry is None:
|
||||
can_be_calculated = False
|
||||
if levels_of_detail.geometry < 1:
|
||||
can_be_calculated = False
|
||||
if levels_of_detail.construction is None:
|
||||
can_be_calculated = False
|
||||
if levels_of_detail.construction < 1:
|
||||
can_be_calculated = False
|
||||
if levels_of_detail.usage is None:
|
||||
can_be_calculated = False
|
||||
if levels_of_detail.usage < 1:
|
||||
can_be_calculated = False
|
||||
if levels_of_detail.weather is None:
|
||||
can_be_calculated = False
|
||||
if levels_of_detail.weather < 2:
|
||||
can_be_calculated = False
|
||||
if levels_of_detail.surface_radiation is None:
|
||||
can_be_calculated = False
|
||||
if levels_of_detail.surface_radiation < 2:
|
||||
can_be_calculated = False
|
||||
return can_be_calculated
|
||||
|
||||
cooling_load_latent = 0
|
||||
cooling_load = cooling_load_sensible + cooling_load_latent
|
||||
if cooling_load > 0:
|
||||
cooling_load = 0
|
||||
monthly_cooling_loads.append(abs(cooling_load))
|
||||
return monthly_cooling_loads
|
||||
@staticmethod
|
||||
def peak_loads_from_hourly(hourly_values):
|
||||
month = 1
|
||||
peaks = [0 for _ in range(12)]
|
||||
for i, value in enumerate(hourly_values):
|
||||
if _MONTH_STARTING_HOUR[month] <= i:
|
||||
month += 1
|
||||
if value > peaks[month-1]:
|
||||
peaks[month-1] = value
|
||||
return peaks
|
||||
|
||||
@property
|
||||
def heating_peak_loads_from_methodology(self):
|
||||
if not self._can_be_calculated():
|
||||
return None
|
||||
monthly_heating_loads = []
|
||||
ambient_temperature = self._building.external_temperature[cte.HOUR]['epw']
|
||||
for month in range(0, 12):
|
||||
ground_temperature = self._building.ground_temperature[cte.MONTH]['2'][month]
|
||||
heating_ambient_temperature = 100
|
||||
start_hour = _MONTH_STARTING_HOUR[month]
|
||||
end_hour = 8760
|
||||
if month < 11:
|
||||
end_hour = _MONTH_STARTING_HOUR[month + 1]
|
||||
for hour in range(start_hour, end_hour):
|
||||
temperature = ambient_temperature[hour]
|
||||
if temperature < heating_ambient_temperature:
|
||||
heating_ambient_temperature = temperature
|
||||
loads = LoadsCalculation(self._building)
|
||||
heating_load_transmitted = loads.get_heating_transmitted_load(heating_ambient_temperature, ground_temperature)
|
||||
heating_load_ventilation_sensible = loads.get_heating_ventilation_load_sensible(heating_ambient_temperature)
|
||||
heating_load_ventilation_latent = 0
|
||||
heating_load = heating_load_transmitted + heating_load_ventilation_sensible + heating_load_ventilation_latent
|
||||
if heating_load < 0:
|
||||
heating_load = 0
|
||||
monthly_heating_loads.append(heating_load)
|
||||
return monthly_heating_loads
|
||||
|
||||
@property
|
||||
def cooling_peak_loads_from_methodology(self):
|
||||
if not self._can_be_calculated():
|
||||
return None
|
||||
monthly_cooling_loads = []
|
||||
ambient_temperature = self._building.external_temperature[cte.HOUR]['epw']
|
||||
for month in range(0, 12):
|
||||
ground_temperature = self._building.ground_temperature[cte.MONTH]['2'][month]
|
||||
cooling_ambient_temperature = -100
|
||||
cooling_calculation_hour = -1
|
||||
start_hour = _MONTH_STARTING_HOUR[month]
|
||||
end_hour = 8760
|
||||
if month < 11:
|
||||
end_hour = _MONTH_STARTING_HOUR[month + 1]
|
||||
for hour in range(start_hour, end_hour):
|
||||
temperature = ambient_temperature[hour]
|
||||
if temperature > cooling_ambient_temperature:
|
||||
cooling_ambient_temperature = temperature
|
||||
cooling_calculation_hour = hour
|
||||
loads = LoadsCalculation(self._building)
|
||||
cooling_load_transmitted = loads.get_cooling_transmitted_load(cooling_ambient_temperature, ground_temperature)
|
||||
cooling_load_renovation_sensible = loads.get_cooling_ventilation_load_sensible(cooling_ambient_temperature)
|
||||
cooling_load_internal_gains_sensible = loads.get_internal_load_sensible()
|
||||
cooling_load_radiation = loads.get_radiation_load('sra', cooling_calculation_hour)
|
||||
cooling_load_sensible = cooling_load_transmitted + cooling_load_renovation_sensible - cooling_load_radiation \
|
||||
- cooling_load_internal_gains_sensible
|
||||
|
||||
cooling_load_latent = 0
|
||||
cooling_load = cooling_load_sensible + cooling_load_latent
|
||||
if cooling_load > 0:
|
||||
cooling_load = 0
|
||||
monthly_cooling_loads.append(abs(cooling_load))
|
||||
return monthly_cooling_loads
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import logging as logger
|
||||
from pathlib import Path
|
||||
import os
|
||||
import logging
|
||||
import sys
|
||||
|
||||
|
||||
|
@ -27,7 +26,6 @@ def get_logger(file_logger=False):
|
|||
except IOError as err:
|
||||
print(f'I/O exception: {err}')
|
||||
else:
|
||||
logging.getLogger().addHandler(logging.StreamHandler(stream=sys.stdout))
|
||||
logging.getLogger().setLevel(logging.DEBUG)
|
||||
logger.getLogger().addHandler(logger.StreamHandler(stream=sys.stdout))
|
||||
logger.getLogger().setLevel(logger.DEBUG)
|
||||
return logger.getLogger()
|
||||
|
||||
|
|
|
@ -4,9 +4,11 @@ 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 math
|
||||
import sys
|
||||
from hub.hub_logger import get_logger
|
||||
from hub.hub_logger import logger
|
||||
|
||||
import hub.helpers.constants as cte
|
||||
from hub.catalog_factories.construction_catalog_factory import ConstructionCatalogFactory
|
||||
|
@ -16,17 +18,13 @@ from hub.helpers.dictionaries import Dictionaries
|
|||
from hub.imports.construction.helpers.construction_helper import ConstructionHelper
|
||||
from hub.imports.construction.helpers.storeys_generation import StoreysGeneration
|
||||
|
||||
logger = get_logger()
|
||||
|
||||
|
||||
class NrcanPhysicsParameters:
|
||||
"""
|
||||
NrcanPhysicsParameters class
|
||||
"""
|
||||
def __init__(self, city, base_path, divide_in_storeys=False):
|
||||
# create a thread pool with 8 threads
|
||||
def __init__(self, city, divide_in_storeys=False):
|
||||
self._city = city
|
||||
self._path = base_path
|
||||
self._divide_in_storeys = divide_in_storeys
|
||||
self._climate_zone = ConstructionHelper.city_to_nrcan_climate_zone(city.name)
|
||||
|
||||
|
@ -46,7 +44,8 @@ class NrcanPhysicsParameters:
|
|||
f'{function} [{building.function}], building year of construction: {building.year_of_construction} '
|
||||
f'and climate zone {self._climate_zone}\n')
|
||||
sys.stderr.write(f'Building {building.name} has unknown construction archetype for building function: '
|
||||
f'{function} [{building.function}], building year of construction: {building.year_of_construction} '
|
||||
f'{function} [{building.function}], '
|
||||
f'building year of construction: {building.year_of_construction} '
|
||||
f'and climate zone {self._climate_zone}\n')
|
||||
continue
|
||||
|
||||
|
@ -68,7 +67,6 @@ class NrcanPhysicsParameters:
|
|||
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:
|
||||
|
|
|
@ -23,9 +23,8 @@ class NrelPhysicsParameters:
|
|||
NrelPhysicsParameters class
|
||||
"""
|
||||
|
||||
def __init__(self, city, base_path, divide_in_storeys=False):
|
||||
def __init__(self, city, 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)
|
||||
|
||||
|
@ -36,17 +35,18 @@ class NrelPhysicsParameters:
|
|||
city = self._city
|
||||
nrel_catalog = ConstructionCatalogFactory('nrel').catalog
|
||||
for building in city.buildings:
|
||||
function = Dictionaries().hub_function_to_nrel_construction_function[building.function]
|
||||
try:
|
||||
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:
|
||||
logger.error(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')
|
||||
f'{function} [{building.function}], building year of construction: {building.year_of_construction} '
|
||||
f'and climate zone {self._climate_zone}\n')
|
||||
sys.stderr.write(f'Building {building.name} has unknown construction archetype for building function: '
|
||||
f'{building.function} and building year of construction: {building.year_of_construction} '
|
||||
f'and climate zone reference norm {self._climate_zone}\n')
|
||||
f'{function} [{building.function}], '
|
||||
f'building year of construction: {building.year_of_construction} '
|
||||
f'and climate zone {self._climate_zone}\n')
|
||||
|
||||
continue
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
|||
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
from hub.hub_logger import get_logger
|
||||
from hub.helpers.utils import validate_import_export_type
|
||||
from hub.imports.construction.nrel_physics_parameters import NrelPhysicsParameters
|
||||
|
@ -19,9 +18,7 @@ class ConstructionFactory:
|
|||
"""
|
||||
ConstructionFactory class
|
||||
"""
|
||||
def __init__(self, handler, city, base_path=None):
|
||||
if base_path is None:
|
||||
base_path = Path(Path(__file__).parent.parent / 'data/construction')
|
||||
def __init__(self, handler, city):
|
||||
self._handler = '_' + handler.lower().replace(' ', '_')
|
||||
class_funcs = validate_import_export_type(ConstructionFactory)
|
||||
if self._handler not in class_funcs:
|
||||
|
@ -29,21 +26,24 @@ class ConstructionFactory:
|
|||
logger.error(err_msg)
|
||||
raise Exception(err_msg)
|
||||
self._city = city
|
||||
self._base_path = base_path
|
||||
|
||||
def _nrel(self):
|
||||
"""
|
||||
Enrich the city by using NREL information
|
||||
"""
|
||||
NrelPhysicsParameters(self._city, self._base_path).enrich_buildings()
|
||||
NrelPhysicsParameters(self._city).enrich_buildings()
|
||||
self._city.level_of_detail.construction = 2
|
||||
for building in self._city.buildings:
|
||||
building.level_of_detail.construction = 2
|
||||
|
||||
def _nrcan(self):
|
||||
"""
|
||||
Enrich the city by using NRCAN information
|
||||
"""
|
||||
NrcanPhysicsParameters(self._city, self._base_path).enrich_buildings()
|
||||
NrcanPhysicsParameters(self._city).enrich_buildings()
|
||||
self._city.level_of_detail.construction = 2
|
||||
for building in self._city.buildings:
|
||||
building.level_of_detail.construction = 2
|
||||
|
||||
def enrich(self):
|
||||
"""
|
||||
|
@ -57,4 +57,4 @@ class ConstructionFactory:
|
|||
Enrich the city given to the class using the class given handler
|
||||
:return: None
|
||||
"""
|
||||
NrelPhysicsParameters(self._city, self._base_path).enrich_buildings()
|
||||
NrelPhysicsParameters(self._city).enrich_buildings()
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
"""
|
||||
Montreal custom energy system importer
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2023 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pandas import DataFrame
|
||||
|
||||
from hub.hub_logger import logger
|
||||
from hub.catalog_factories.energy_systems_catalog_factory import EnergySystemsCatalogFactory
|
||||
from hub.city_model_structure.energy_systems.generic_energy_system import GenericEnergySystem
|
||||
from hub.city_model_structure.energy_systems.generic_generation_system import GenericGenerationSystem
|
||||
from hub.city_model_structure.energy_systems.generic_distribution_system import GenericDistributionSystem
|
||||
from hub.helpers.dictionaries import Dictionaries
|
||||
|
||||
|
||||
class MontrealCustomEnergySystemParameters:
|
||||
"""
|
||||
MontrealCustomEnergySystemParameters class
|
||||
"""
|
||||
|
||||
def __init__(self, city):
|
||||
self._city = city
|
||||
|
||||
def enrich_buildings(self):
|
||||
"""
|
||||
Returns the city with the system parameters assigned to the buildings
|
||||
:return:
|
||||
"""
|
||||
city = self._city
|
||||
montreal_custom_catalog = EnergySystemsCatalogFactory('montreal_custom').catalog
|
||||
if city.energy_systems_connection_table is None:
|
||||
_energy_systems_connection_table = DataFrame(columns=['Energy System Type', 'Building'])
|
||||
else:
|
||||
_energy_systems_connection_table = city.energy_systems_connection_table
|
||||
if city.generic_energy_systems is None:
|
||||
_generic_energy_systems = {}
|
||||
else:
|
||||
_generic_energy_systems = city.generic_energy_systems
|
||||
for building in city.buildings:
|
||||
archetype_name = f'{building.energy_systems_archetype_name}_lod1.0'
|
||||
# archetype_name = building.energy_systems_archetype_name
|
||||
try:
|
||||
archetype = self._search_archetypes(montreal_custom_catalog, archetype_name)
|
||||
except KeyError:
|
||||
logger.error(f'Building {building.name} has unknown energy system archetype for system name: {archetype_name}')
|
||||
sys.stderr.write(f'Building {building.name} has unknown energy system archetype '
|
||||
f'for system name: {archetype_name}')
|
||||
continue
|
||||
|
||||
building_systems = []
|
||||
data = [archetype_name, building.name]
|
||||
_energy_systems_connection_table.loc[len(_energy_systems_connection_table)] = data
|
||||
for equipment in archetype.equipments:
|
||||
energy_system = GenericEnergySystem()
|
||||
_hub_demand_types = []
|
||||
for demand_type in equipment.demand_types:
|
||||
_hub_demand_types.append(Dictionaries().montreal_demand_type_to_hub_energy_demand_type[demand_type])
|
||||
energy_system.name = archetype_name
|
||||
energy_system.demand_types = _hub_demand_types
|
||||
_generation_system = GenericGenerationSystem()
|
||||
archetype_generation_equipment = equipment.generation_system
|
||||
_type = str(equipment.name).split('_')[0]
|
||||
_generation_system.type = Dictionaries().montreal_system_to_hub_energy_generation_system[
|
||||
_type]
|
||||
_generation_system.fuel_type = archetype_generation_equipment.fuel_type
|
||||
_generation_system.source_types = archetype_generation_equipment.source_types
|
||||
_generation_system.heat_efficiency = archetype_generation_equipment.heat_efficiency
|
||||
_generation_system.cooling_efficiency = archetype_generation_equipment.cooling_efficiency
|
||||
_generation_system.electricity_efficiency = archetype_generation_equipment.electricity_efficiency
|
||||
_generation_system.source_temperature = archetype_generation_equipment.source_temperature
|
||||
_generation_system.source_mass_flow = archetype_generation_equipment.source_mass_flow
|
||||
_generation_system.storage = archetype_generation_equipment.storage
|
||||
_generation_system.auxiliary_equipment = None
|
||||
|
||||
energy_system.generation_system = _generation_system
|
||||
|
||||
_distribution_system = GenericDistributionSystem()
|
||||
archetype_distribution_equipment = equipment.distribution_system
|
||||
_distribution_system.type = archetype_distribution_equipment.type
|
||||
_distribution_system.supply_temperature = archetype_distribution_equipment.supply_temperature
|
||||
_distribution_system.distribution_consumption = archetype_distribution_equipment.distribution_consumption
|
||||
_distribution_system.heat_losses = archetype_distribution_equipment.heat_losses
|
||||
|
||||
energy_system.distribution_system = _distribution_system
|
||||
|
||||
building_systems.append(energy_system)
|
||||
if archetype_name not in _generic_energy_systems:
|
||||
_generic_energy_systems[archetype_name] = building_systems
|
||||
|
||||
city.energy_systems_connection_table = _energy_systems_connection_table
|
||||
city.generic_energy_systems = _generic_energy_systems
|
||||
|
||||
@staticmethod
|
||||
def _search_archetypes(catalog, name):
|
||||
archetypes = catalog.entries('archetypes')
|
||||
for building_archetype in archetypes:
|
||||
if str(name) == str(building_archetype.name):
|
||||
return building_archetype
|
||||
raise KeyError('archetype not found')
|
|
@ -10,6 +10,7 @@ from hub.imports.energy_systems.air_source_hp_parameters import AirSourceHeatPum
|
|||
from hub.imports.energy_systems.water_to_water_hp_parameters import WaterToWaterHPParameters
|
||||
from hub.helpers.utils import validate_import_export_type
|
||||
from hub.hub_logger import get_logger
|
||||
from hub.imports.energy_systems.montreal_custom_energy_system_parameters import MontrealCustomEnergySystemParameters
|
||||
|
||||
logger = get_logger()
|
||||
|
||||
|
@ -36,12 +37,27 @@ class EnergySystemsFactory:
|
|||
Enrich the city by using xlsx heat pump information
|
||||
"""
|
||||
AirSourceHeatPumpParameters(self._city, self._base_path).enrich_city()
|
||||
self._city.level_of_detail.energy_systems = 0
|
||||
for building in self._city.buildings:
|
||||
building.level_of_detail.energy_systems = 0
|
||||
|
||||
def _water_to_water_hp(self):
|
||||
"""
|
||||
Enrich the city by using water to water heat pump information
|
||||
"""
|
||||
WaterToWaterHPParameters(self._city, self._base_path).enrich_city()
|
||||
self._city.level_of_detail.energy_systems = 0
|
||||
for building in self._city.buildings:
|
||||
building.level_of_detail.energy_systems = 0
|
||||
|
||||
def _montreal_custom(self):
|
||||
"""
|
||||
Enrich the city by using montreal custom energy systems catalog information
|
||||
"""
|
||||
MontrealCustomEnergySystemParameters(self._city).enrich_buildings()
|
||||
self._city.level_of_detail.energy_systems = 1
|
||||
for building in self._city.buildings:
|
||||
building.level_of_detail.energy_systems = 1
|
||||
|
||||
def enrich(self):
|
||||
"""
|
||||
|
|
|
@ -166,4 +166,6 @@ class CityGml:
|
|||
else:
|
||||
self._city.add_city_object(self._create_building(city_object))
|
||||
self._city.level_of_detail.geometry = self._lod
|
||||
for building in self._city.buildings:
|
||||
building.level_of_detail.geometry = self._lod
|
||||
return self._city
|
||||
|
|
|
@ -115,7 +115,7 @@ class Geojson:
|
|||
extrusion_height = 0
|
||||
if self._extrusion_height_field is not None:
|
||||
extrusion_height = float(feature['properties'][self._extrusion_height_field])
|
||||
lod = 0.5
|
||||
lod = 1
|
||||
year_of_construction = None
|
||||
if self._year_of_construction_field is not None:
|
||||
year_of_construction = int(feature['properties'][self._year_of_construction_field])
|
||||
|
@ -154,6 +154,8 @@ class Geojson:
|
|||
if building.floor_area >= 25:
|
||||
self._city.add_city_object(building)
|
||||
self._city.level_of_detail.geometry = lod
|
||||
for building in self._city.buildings:
|
||||
building.level_of_detail.geometry = lod
|
||||
if lod > 0:
|
||||
lines_information = GeometryHelper.city_mapping(self._city, plot=False)
|
||||
self._store_shared_percentage_to_walls(self._city, lines_information)
|
||||
|
|
|
@ -83,6 +83,8 @@ class GPandas:
|
|||
building = Building(name, surfaces, year_of_construction, function, terrains=None)
|
||||
self._city.add_city_object(building)
|
||||
self._city.level_of_detail.geometry = lod
|
||||
for building in self._city.buildings:
|
||||
building.level_of_detail.geometry = lod
|
||||
return self._city
|
||||
|
||||
@staticmethod
|
||||
|
|
|
@ -81,4 +81,7 @@ class Obj:
|
|||
building = Building(name, surfaces, year_of_construction, function, terrains=None)
|
||||
self._city.add_city_object(building)
|
||||
self._city.level_of_detail.geometry = lod
|
||||
for building in self._city.buildings:
|
||||
building.level_of_detail.geometry = lod
|
||||
|
||||
return self._city
|
||||
|
|
|
@ -133,5 +133,6 @@ class Rhino:
|
|||
|
||||
for building in buildings:
|
||||
city.add_city_object(building)
|
||||
building.level_of_detail.geometry = 3
|
||||
city.level_of_detail.geometry = 3
|
||||
return city
|
||||
|
|
|
@ -87,9 +87,20 @@ class InselMonthlyEnergyBalance:
|
|||
total_dhw_demand += total_day * cte.DAYS_A_MONTH[day_type][month] * demand
|
||||
domestic_hot_water_demand.append(total_dhw_demand * area)
|
||||
|
||||
building.domestic_hot_water_heat_demand[cte.MONTH] = pd.DataFrame(domestic_hot_water_demand, columns=[cte.INSEL_MEB])
|
||||
building.domestic_hot_water_heat_demand[cte.MONTH] = pd.DataFrame(domestic_hot_water_demand,
|
||||
columns=[cte.INSEL_MEB])
|
||||
yearly_domestic_hot_water_demand = [sum(domestic_hot_water_demand)]
|
||||
building.domestic_hot_water_heat_demand[cte.YEAR] = pd.DataFrame(yearly_domestic_hot_water_demand,
|
||||
columns=[cte.INSEL_MEB])
|
||||
building.lighting_electrical_demand[cte.MONTH] = pd.DataFrame(lighting_demand, columns=[cte.INSEL_MEB])
|
||||
yearly_lighting_electrical_demand = [sum(lighting_demand)]
|
||||
building.lighting_electrical_demand[cte.YEAR] = pd.DataFrame(yearly_lighting_electrical_demand,
|
||||
columns=[cte.INSEL_MEB])
|
||||
building.appliances_electrical_demand[cte.MONTH] = pd.DataFrame(appliances_demand, columns=[cte.INSEL_MEB])
|
||||
yearly_appliances_electrical_demand = [sum(appliances_demand)]
|
||||
building.appliances_electrical_demand[cte.YEAR] = pd.DataFrame(yearly_appliances_electrical_demand,
|
||||
columns=[cte.INSEL_MEB])
|
||||
|
||||
|
||||
def enrich(self):
|
||||
for building in self._city.buildings:
|
||||
|
|
|
@ -95,3 +95,6 @@ class SimplifiedRadiosityAlgorithm:
|
|||
if cte.YEAR not in surface.global_irradiance:
|
||||
surface.global_irradiance[cte.YEAR] = self._get_yearly_mean_values(new_value)
|
||||
self._city.level_of_detail.surface_radiation = 2
|
||||
for building in self._city.buildings:
|
||||
building.level_of_detail.surface_radiation = 2
|
||||
|
||||
|
|
|
@ -28,9 +28,8 @@ class ComnetUsageParameters:
|
|||
"""
|
||||
ComnetUsageParameters class
|
||||
"""
|
||||
def __init__(self, city, base_path):
|
||||
def __init__(self, city):
|
||||
self._city = city
|
||||
self._path = base_path
|
||||
|
||||
def enrich_buildings(self):
|
||||
"""
|
||||
|
|
|
@ -25,9 +25,8 @@ class NrcanUsageParameters:
|
|||
"""
|
||||
NrcanUsageParameters class
|
||||
"""
|
||||
def __init__(self, city, base_path):
|
||||
def __init__(self, city):
|
||||
self._city = city
|
||||
self._path = base_path
|
||||
|
||||
def enrich_buildings(self):
|
||||
"""
|
||||
|
@ -132,11 +131,16 @@ class NrcanUsageParameters:
|
|||
def _assign_comnet_extra_values(usage, archetype, occupancy_density):
|
||||
_occupancy = usage.occupancy
|
||||
archetype_density = archetype.occupancy.occupancy_density
|
||||
_occupancy.sensible_radiative_internal_gain = archetype.occupancy.sensible_radiative_internal_gain \
|
||||
* occupancy_density / archetype_density
|
||||
_occupancy.latent_internal_gain = archetype.occupancy.latent_internal_gain * occupancy_density / archetype_density
|
||||
_occupancy.sensible_convective_internal_gain = archetype.occupancy.sensible_convective_internal_gain \
|
||||
* occupancy_density / archetype_density
|
||||
if archetype_density == 0:
|
||||
_occupancy.sensible_radiative_internal_gain = 0
|
||||
_occupancy.latent_internal_gain = 0
|
||||
_occupancy.sensible_convective_internal_gain = 0
|
||||
else:
|
||||
_occupancy.sensible_radiative_internal_gain = archetype.occupancy.sensible_radiative_internal_gain \
|
||||
* occupancy_density / archetype_density
|
||||
_occupancy.latent_internal_gain = archetype.occupancy.latent_internal_gain * occupancy_density / archetype_density
|
||||
_occupancy.sensible_convective_internal_gain = archetype.occupancy.sensible_convective_internal_gain \
|
||||
* occupancy_density / archetype_density
|
||||
|
||||
@staticmethod
|
||||
def _calculate_reduced_values_from_extended_library(usage, archetype):
|
||||
|
|
|
@ -6,7 +6,7 @@ Copyright © 2022 Concordia CERC group
|
|||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
from pathlib import Path
|
||||
|
||||
from hub.imports.usage.comnet_usage_parameters import ComnetUsageParameters
|
||||
from hub.imports.usage.nrcan_usage_parameters import NrcanUsageParameters
|
||||
from hub.hub_logger import get_logger
|
||||
|
@ -19,9 +19,7 @@ class UsageFactory:
|
|||
"""
|
||||
UsageFactory class
|
||||
"""
|
||||
def __init__(self, handler, city, base_path=None):
|
||||
if base_path is None:
|
||||
base_path = Path(Path(__file__).parent.parent / 'data/usage')
|
||||
def __init__(self, handler, city):
|
||||
self._handler = '_' + handler.lower().replace(' ', '_')
|
||||
class_funcs = validate_import_export_type(UsageFactory)
|
||||
if self._handler not in class_funcs:
|
||||
|
@ -29,21 +27,24 @@ class UsageFactory:
|
|||
logger.error(err_msg)
|
||||
raise Exception(err_msg)
|
||||
self._city = city
|
||||
self._base_path = base_path
|
||||
|
||||
def _comnet(self):
|
||||
"""
|
||||
Enrich the city with COMNET usage library
|
||||
"""
|
||||
ComnetUsageParameters(self._city).enrich_buildings()
|
||||
self._city.level_of_detail.usage = 2
|
||||
ComnetUsageParameters(self._city, self._base_path).enrich_buildings()
|
||||
for building in self._city.buildings:
|
||||
building.level_of_detail.usage = 2
|
||||
|
||||
def _nrcan(self):
|
||||
"""
|
||||
Enrich the city with NRCAN usage library
|
||||
"""
|
||||
NrcanUsageParameters(self._city).enrich_buildings()
|
||||
self._city.level_of_detail.usage = 2
|
||||
NrcanUsageParameters(self._city, self._base_path).enrich_buildings()
|
||||
for building in self._city.buildings:
|
||||
building.level_of_detail.usage = 2
|
||||
|
||||
def enrich(self):
|
||||
"""
|
||||
|
|
|
@ -160,3 +160,6 @@ class EpwWeatherParameters:
|
|||
usage.domestic_hot_water.density = density
|
||||
|
||||
self._city.level_of_detail.weather = 2
|
||||
for building in self._city.buildings:
|
||||
building.level_of_detail.weather = 2
|
||||
|
||||
|
|
|
@ -8,10 +8,7 @@ from pathlib import Path
|
|||
from unittest import TestCase
|
||||
|
||||
import hub.exports.exports_factory
|
||||
from hub.imports.usage_factory import UsageFactory
|
||||
|
||||
from hub.exports.energy_building_exports_factory import EnergyBuildingsExportsFactory
|
||||
from hub.helpers.dictionaries import MontrealFunctionToHubFunction, Dictionaries
|
||||
from hub.helpers.dictionaries import MontrealFunctionToHubFunction
|
||||
from hub.helpers.geometry_helper import GeometryHelper
|
||||
from hub.imports.construction_factory import ConstructionFactory
|
||||
from hub.imports.geometry_factory import GeometryFactory
|
||||
|
|
33
hub/unittests/test_systems_catalog.py
Normal file
33
hub/unittests/test_systems_catalog.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
"""
|
||||
TestSystemsCatalog
|
||||
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 unittest import TestCase
|
||||
from hub.catalog_factories.energy_systems_catalog_factory import EnergySystemsCatalogFactory
|
||||
|
||||
|
||||
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']))
|
||||
with self.assertRaises(ValueError):
|
||||
catalog.names('unknown')
|
||||
|
||||
# retrieving all the entries should not raise any exceptions
|
||||
for category in catalog_categories:
|
||||
for value in catalog_categories[category]:
|
||||
catalog.get_entry(value)
|
||||
|
||||
with self.assertRaises(IndexError):
|
||||
catalog.get_entry('unknown')
|
110
hub/unittests/test_systems_factory.py
Normal file
110
hub/unittests/test_systems_factory.py
Normal file
|
@ -0,0 +1,110 @@
|
|||
"""
|
||||
TestSystemsFactory
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2023 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from unittest import TestCase
|
||||
import copy
|
||||
|
||||
import hub.helpers.constants as cte
|
||||
from hub.exports.energy_building_exports_factory import EnergyBuildingsExportsFactory
|
||||
from hub.exports.exports_factory import ExportsFactory
|
||||
from hub.helpers.dictionaries import Dictionaries
|
||||
from hub.imports.construction_factory import ConstructionFactory
|
||||
from hub.imports.geometry_factory import GeometryFactory
|
||||
from hub.imports.results_factory import ResultFactory
|
||||
from hub.imports.usage_factory import UsageFactory
|
||||
from hub.imports.energy_systems_factory import EnergySystemsFactory
|
||||
from hub.city_model_structure.energy_systems.energy_system import EnergySystem
|
||||
from hub.city_model_structure.energy_systems.generation_system import GenerationSystem
|
||||
from hub.city_model_structure.energy_systems.distribution_system import DistributionSystem
|
||||
from hub.city_model_structure.energy_systems.emission_system import EmissionSystem
|
||||
|
||||
|
||||
class TestSystemsFactory(TestCase):
|
||||
"""
|
||||
TestSystemsFactory TestCase
|
||||
"""
|
||||
def setUp(self) -> None:
|
||||
"""
|
||||
Test setup
|
||||
:return: None
|
||||
"""
|
||||
self._example_path = (Path(__file__).parent / 'tests_data').resolve()
|
||||
self._gml_path = (self._example_path / 'FZK_Haus_LoD_2.gml').resolve()
|
||||
self._output_path = (Path(__file__).parent / 'tests_outputs').resolve()
|
||||
self._city = GeometryFactory('citygml',
|
||||
self._gml_path,
|
||||
function_to_hub=Dictionaries().alkis_function_to_hub_function).city
|
||||
|
||||
def test_montreal_custom_system_factory(self):
|
||||
"""
|
||||
Enrich the city with the construction information and verify it
|
||||
"""
|
||||
for building in self._city.buildings:
|
||||
building.energy_systems_archetype_name = 'system 1 gas'
|
||||
|
||||
EnergySystemsFactory('montreal_custom', self._city).enrich()
|
||||
self.assertEqual(1, len(self._city.energy_systems_connection_table))
|
||||
|
||||
def test_montreal_custom_system_results(self):
|
||||
"""
|
||||
Enrich the city with the construction information and verify it
|
||||
"""
|
||||
ConstructionFactory('nrcan', self._city).enrich()
|
||||
UsageFactory('nrcan', self._city).enrich()
|
||||
weather_file = (self._example_path / 'CAN_PQ_Montreal.Intl.AP.716270_CWEC.epw').resolve()
|
||||
ExportsFactory('sra', self._city, self._output_path, weather_file=weather_file, weather_format='epw').export()
|
||||
sra_path = (self._output_path / f'{self._city.name}_sra.xml').resolve()
|
||||
subprocess.run(['sra', str(sra_path)])
|
||||
ResultFactory('sra', self._city, self._output_path).enrich()
|
||||
EnergyBuildingsExportsFactory('insel_monthly_energy_balance', self._city, self._output_path).export()
|
||||
for building in self._city.buildings:
|
||||
insel_path = (self._output_path / f'{building.name}.insel')
|
||||
subprocess.run(['insel', str(insel_path)])
|
||||
ResultFactory('insel_monthly_energy_balance', self._city, self._output_path).enrich()
|
||||
self._city.save(self._output_path / 'city.pickle')
|
||||
|
||||
for building in self._city.buildings:
|
||||
building.energy_systems_archetype_name = 'system 1 gas'
|
||||
EnergySystemsFactory('montreal_custom', self._city).enrich()
|
||||
# Need to assign energy systems to buildings:
|
||||
energy_systems_connection = self._city.energy_systems_connection_table
|
||||
for building in self._city.buildings:
|
||||
_building_energy_systems = []
|
||||
energy_systems = energy_systems_connection['Energy System Type']\
|
||||
.where(energy_systems_connection['Building'] == building.name)
|
||||
for energy_system in energy_systems:
|
||||
_generic_building_energy_systems = self._city.generic_energy_systems[energy_system]
|
||||
for _generic_building_energy_system in _generic_building_energy_systems:
|
||||
_building_energy_equipment = EnergySystem()
|
||||
_building_energy_equipment.demand_types = _generic_building_energy_system.demand_types
|
||||
|
||||
_building_distribution_system = DistributionSystem()
|
||||
_building_distribution_system.generic_distribution_system = \
|
||||
copy.deepcopy(_generic_building_energy_system.distribution_system)
|
||||
_building_emission_system = EmissionSystem()
|
||||
_building_emission_system.generic_emission_system = \
|
||||
copy.deepcopy(_generic_building_energy_system.emission_system)
|
||||
_building_generation_system = GenerationSystem()
|
||||
_building_generation_system.generic_generation_system = \
|
||||
copy.deepcopy(_generic_building_energy_system.generation_system)
|
||||
if cte.HEATING in _building_energy_equipment.demand_types:
|
||||
_building_generation_system.heat_power = building.heating_peak_load[cte.YEAR]['heating peak loads'][0]
|
||||
if cte.COOLING in _building_energy_equipment.demand_types:
|
||||
_building_generation_system.cooling_power = building.cooling_peak_load[cte.YEAR]['cooling peak loads'][0]
|
||||
_building_energy_equipment.generation_system = _building_generation_system
|
||||
_building_energy_equipment.distribution_system = _building_distribution_system
|
||||
_building_energy_equipment.emission_system = _building_emission_system
|
||||
|
||||
_building_energy_systems.append(_building_energy_equipment)
|
||||
building.energy_systems = _building_energy_systems
|
||||
|
||||
for building in self._city.buildings:
|
||||
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])
|
Loading…
Reference in New Issue
Block a user