Saved local changes

This commit is contained in:
Peter Yefi 2023-02-19 14:04:11 -05:00
commit f4ce207284
157 changed files with 5597 additions and 6111 deletions

8
hub/.gitignore vendored
View File

@ -1,10 +1,12 @@
!.gitignore !.gitignore
/venv/ **/venv/
.idea/ .idea/
/development_tests/ /development_tests/
/data/energy_systems/heat_pumps/*.csv /data/energy_systems/heat_pumps/*.csv
/data/energy_systems/heat_pumps/*.insel /data/energy_systems/heat_pumps/*.insel
.DS_Store .DS_Store
.env **/.env
hub/logs **/hub/logs/
**/__pycache__/ **/__pycache__/
**/.idea/

View File

@ -1,5 +1,20 @@
## Installing PostgreSQL Database Server on Linux (Ubuntu) ## ## Installing PostgreSQL Database Server on Linux (Ubuntu) ##
Execute the *install_postgresql_linux.sh* script to install PostgreSQL database
In the terminal, add the key to the keyring
`
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
`
Update your repositories with
`sudo apt-get update`
Install postgresql
sudo apt-get install postgresql
`
*NB: PostgreSQL DB Server runs on a default port of 5432.* *NB: PostgreSQL DB Server runs on a default port of 5432.*
## Installing PostgreSQL Database Server on Windows ## ## Installing PostgreSQL Database Server on Windows ##
@ -59,7 +74,7 @@ from hub.persistence import DBSetup
from pathlib import Path from pathlib import Path
dotenv_path = (Path(__file__).parent / '.env').resolve() dotenv_path = (Path(__file__).parent / '.env').resolve()
DBSetup(db_name='hub_db', app_env='PROD', dotenv_path=dotenv_path) DBSetup(db_name='hub_db', app_env='PROD', dotenv_path=dotenv_path, admin_password="your password here", application_uuid="your admin application uuid")
``` ```
The *DBSetUp* class also creates a default admin user with default credentials that can be changed. The *DBSetUp* class also creates a default admin user with default credentials that can be changed.
with the import UserFactory class. The admin user (name, email, password and role) is logged into the console after it is created by the with the import UserFactory class. The admin user (name, email, password and role) is logged into the console after it is created by the

View File

@ -0,0 +1,46 @@
from hub.helpers import constants as cte
class ConstructionHelper:
"""
Construction helper class
"""
_reference_standard_to_construction_period = {
'non_standard_dompark': '1900 - 2004',
'ASHRAE 90.1_2004': '2004 - 2009',
'ASHRAE 189.1_2009': '2009 - PRESENT'
}
_nrel_surfaces_types_to_hub_types = {
'exterior wall': cte.WALL,
'interior wall': cte.INTERIOR_WALL,
'ground wall': cte.GROUND_WALL,
'exterior slab': cte.GROUND,
'attic floor': cte.ATTIC_FLOOR,
'interior slab': cte.INTERIOR_SLAB,
'roof': cte.ROOF
}
_nrcan_surfaces_types_to_hub_types = {
'Wall_Outdoors': cte.WALL,
'RoofCeiling_Outdoors': cte.ROOF,
'Floor_Outdoors': cte.ATTIC_FLOOR,
'Window_Outdoors': cte.WINDOW,
'Skylight_Outdoors': cte.SKYLIGHT,
'Door_Outdoors': cte.DOOR,
'Wall_Ground': cte.GROUND_WALL,
'RoofCeiling_Ground': cte.GROUND_WALL,
'Floor_Ground': cte.GROUND
}
@property
def reference_standard_to_construction_period(self):
return self._reference_standard_to_construction_period
@property
def nrel_surfaces_types_to_hub_types(self):
return self._nrel_surfaces_types_to_hub_types
@property
def nrcan_surfaces_types_to_hub_types(self):
return self._nrcan_surfaces_types_to_hub_types

View File

@ -1,43 +0,0 @@
from hub.helpers import constants as cte
nrel_to_function = {
'residential': cte.RESIDENTIAL,
'midrise apartment': cte.MID_RISE_APARTMENT,
'high-rise apartment': cte.HIGH_RISE_APARTMENT,
'small office': cte.SMALL_OFFICE,
'medium office': cte.MEDIUM_OFFICE,
'large office': cte.LARGE_OFFICE,
'primary school': cte.PRIMARY_SCHOOL,
'secondary school': cte.SECONDARY_SCHOOL,
'stand-alone retail': cte.STAND_ALONE_RETAIL,
'hospital': cte.HOSPITAL,
'outpatient healthcare': cte.OUT_PATIENT_HEALTH_CARE,
'strip mall': cte.STRIP_MALL,
'supermarket': cte.SUPERMARKET,
'warehouse': cte.WAREHOUSE,
'quick service restaurant': cte.QUICK_SERVICE_RESTAURANT,
'full service restaurant': cte.FULL_SERVICE_RESTAURANT,
'small hotel': cte.SMALL_HOTEL,
'large hotel': cte.LARGE_HOTEL,
'industry': cte.INDUSTRY
}
nrcan_to_function = {
'residential': cte.RESIDENTIAL,
}
reference_standard_to_construction_period = {
'non_standard_dompark': '1900 - 2004',
'ASHRAE 90.1_2004': '2004 - 2009',
'ASHRAE 189.1_2009': '2009 - PRESENT'
}
nrel_surfaces_types_to_hub_types = {
'exterior wall': cte.WALL,
'interior wall': cte.INTERIOR_WALL,
'ground wall': cte.GROUND_WALL,
'exterior slab': cte.GROUND,
'attic floor': cte.ATTIC_FLOOR,
'interior slab': cte.INTERIOR_SLAB,
'roof': cte.ROOF
}

View File

@ -0,0 +1,124 @@
"""
NRCAN construction catalog
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import json
import urllib.request
import xmltodict
from hub.catalog_factories.catalog import Catalog
from hub.catalog_factories.data_models.usages.content import Content
from hub.catalog_factories.construction.construction_helper import ConstructionHelper
from hub.catalog_factories.data_models.construction.construction import Construction
from hub.catalog_factories.data_models.construction.archetype import Archetype
class NrcanCatalog(Catalog):
def __init__(self, path):
path = str(path / 'nrcan.xml')
self._content = None
self._g_value_per_hdd = []
self._thermal_transmittance_per_hdd_and_surface = {}
self._window_ratios = {}
with open(path) as xml:
self._metadata = xmltodict.parse(xml.read())
self._base_url_archetypes = self._metadata['nrcan']['@base_url_archetypes']
self._base_url_construction = self._metadata['nrcan']['@base_url_construction']
self._load_window_ratios()
self._load_construction_values()
self._content = Content(self._load_archetypes())
def _load_window_ratios(self):
for standard in self._metadata['nrcan']['standards_per_function']['standard']:
url = f'{self._base_url_archetypes}{standard["file_location"]}'
# todo: read from file
self._window_ratios = {'Mean': 0.2, 'North': 0.2, 'East': 0.2, 'South': 0.2, 'West': 0.2}
def _load_construction_values(self):
for standard in self._metadata['nrcan']['standards_per_period']['standard']:
g_value_url = f'{self._base_url_construction}{standard["g_value_location"]}'
punc = '()<?:'
with urllib.request.urlopen(g_value_url) as json_file:
text = json.load(json_file)['tables']['SHGC']['table'][0]['formula']
values = ''.join([o for o in list(text) if o not in punc]).split()
for index in range(int((len(values) - 1)/3)):
self._g_value_per_hdd.append([values[3*index+1], values[3*index+2]])
self._g_value_per_hdd.append(['15000', values[len(values)-1]])
construction_url = f'{self._base_url_construction}{standard["constructions_location"]}'
with urllib.request.urlopen(construction_url) as json_file:
cases = json.load(json_file)['tables']['surface_thermal_transmittance']['table']
# W/m2K
for case in cases:
surface = \
ConstructionHelper().nrcan_surfaces_types_to_hub_types[f"{case['surface']}_{case['boundary_condition']}"]
thermal_transmittance_per_hdd = []
text = case['formula']
values = ''.join([o for o in list(text) if o not in punc]).split()
for index in range(int((len(values) - 1)/3)):
thermal_transmittance_per_hdd.append([values[3*index+1], values[3*index+2]])
thermal_transmittance_per_hdd.append(['15000', values[len(values)-1]])
self._thermal_transmittance_per_hdd_and_surface[surface] = thermal_transmittance_per_hdd
def _load_constructions(self, window_ratio_standard, construction_standard):
constructions = []
# todo: we need to save the total transmittance somehow, we don't do it yet in our archetypes
# todo: it has to be selected the specific thermal_transmittance from
# self._thermal_transmittance_per_hdd_and_surface and window_ratios from self._window_ratios for each standard case
for i, surface_type in enumerate(self._thermal_transmittance_per_hdd_and_surface):
constructions.append(Construction(i, surface_type, None, None, self._window_ratios))
return constructions
def _load_archetypes(self):
archetypes = []
archetype_id = 0
for window_ratio_standard in self._metadata['nrcan']['standards_per_function']['standard']:
for construction_standard in self._metadata['nrcan']['standards_per_period']['standard']:
archetype_id += 1
function = window_ratio_standard['@function']
climate_zone = 'Montreal'
construction_period = construction_standard['@period_of_construction']
constructions = self._load_constructions(window_ratio_standard, construction_standard)
archetypes.append(Archetype(archetype_id,
None,
function,
climate_zone,
construction_period,
constructions,
None,
None,
None,
None,
None,
None))
return archetypes
def names(self, category=None):
"""
Get the catalog elements names
:parm: for usage catalog category filter does nothing as there is only one category (usages)
"""
_names = {'usages': []}
for usage in self._content.usages:
_names['usages'].append(usage.name)
return _names
def entries(self, category=None):
"""
Get the catalog elements
:parm: for usage catalog category filter does nothing as there is only one category (usages)
"""
return self._content
def get_entry(self, name):
"""
Get one catalog element by names
:parm: entry name
"""
for usage in self._content.usages:
if usage.name.lower() == name.lower():
return usage
raise IndexError(f"{name} doesn't exists in the catalog")

View File

@ -14,9 +14,7 @@ from hub.catalog_factories.data_models.construction.layer import Layer
from hub.catalog_factories.data_models.construction.construction import Construction from hub.catalog_factories.data_models.construction.construction import Construction
from hub.catalog_factories.data_models.construction.content import Content from hub.catalog_factories.data_models.construction.content import Content
from hub.catalog_factories.data_models.construction.archetype import Archetype from hub.catalog_factories.data_models.construction.archetype import Archetype
from hub.catalog_factories.construction.construction_helpers import nrel_to_function from hub.catalog_factories.construction.construction_helper import ConstructionHelper
from hub.catalog_factories.construction.construction_helpers import reference_standard_to_construction_period
from hub.catalog_factories.construction.construction_helpers import nrel_surfaces_types_to_hub_types
class NrelCatalog(Catalog): class NrelCatalog(Catalog):
@ -89,7 +87,7 @@ class NrelCatalog(Catalog):
constructions = self._constructions['library']['constructions']['construction'] constructions = self._constructions['library']['constructions']['construction']
for construction in constructions: for construction in constructions:
construction_id = construction['@id'] construction_id = construction['@id']
construction_type = nrel_surfaces_types_to_hub_types[construction['@type']] construction_type = ConstructionHelper().nrel_surfaces_types_to_hub_types[construction['@type']]
name = construction['@name'] name = construction['@name']
layers = [] layers = []
for layer in construction['layers']['layer']: for layer in construction['layers']['layer']:
@ -111,10 +109,11 @@ class NrelCatalog(Catalog):
archetypes = self._archetypes['archetypes']['archetype'] archetypes = self._archetypes['archetypes']['archetype']
for archetype in archetypes: for archetype in archetypes:
archetype_id = archetype['@id'] archetype_id = archetype['@id']
function = nrel_to_function[archetype['@building_type']] function = archetype['@building_type']
name = f"{function} {archetype['@climate_zone']} {archetype['@reference_standard']}" name = f"{function} {archetype['@climate_zone']} {archetype['@reference_standard']}"
climate_zone = archetype['@climate_zone'] climate_zone = archetype['@climate_zone']
construction_period = reference_standard_to_construction_period[archetype['@reference_standard']] construction_period = \
ConstructionHelper().reference_standard_to_construction_period[archetype['@reference_standard']]
average_storey_height = archetype['average_storey_height']['#text'] average_storey_height = archetype['average_storey_height']['#text']
thermal_capacity = str(float(archetype['thermal_capacity']['#text']) * 1000) thermal_capacity = str(float(archetype['thermal_capacity']['#text']) * 1000)
extra_loses_due_to_thermal_bridges = archetype['extra_loses_due_to_thermal_bridges']['#text'] extra_loses_due_to_thermal_bridges = archetype['extra_loses_due_to_thermal_bridges']['#text']

View File

@ -8,6 +8,9 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
from pathlib import Path from pathlib import Path
from typing import TypeVar from typing import TypeVar
from hub.catalog_factories.construction.nrel_catalog import NrelCatalog from hub.catalog_factories.construction.nrel_catalog import NrelCatalog
from hub.hub_logger import logger
from hub.helpers.utils import validate_import_export_type
from hub.catalog_factories.construction.nrcan_catalog import NrcanCatalog
Catalog = TypeVar('Catalog') Catalog = TypeVar('Catalog')
@ -16,6 +19,11 @@ class ConstructionCatalogFactory:
if base_path is None: if base_path is None:
base_path = Path(Path(__file__).parent.parent / 'data/construction') base_path = Path(Path(__file__).parent.parent / 'data/construction')
self._catalog_type = '_' + file_type.lower() self._catalog_type = '_' + file_type.lower()
class_funcs = validate_import_export_type(ConstructionCatalogFactory)
if self._catalog_type not in class_funcs:
err_msg = f"Wrong import type. Valid functions include {class_funcs}"
logger.error(err_msg)
raise Exception(err_msg)
self._path = base_path self._path = base_path
@property @property
@ -25,6 +33,13 @@ class ConstructionCatalogFactory:
""" """
return NrelCatalog(self._path) return NrelCatalog(self._path)
@property
def _nrcan(self):
"""
Retrieve NREL catalog
"""
return NrcanCatalog(self._path)
@property @property
def catalog(self) -> Catalog: def catalog(self) -> Catalog:
""" """

View File

@ -0,0 +1,170 @@
"""
Cost catalog
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Atiya atiya.atiya@mail.concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import xmltodict
from hub.catalog_factories.catalog import Catalog
from hub.catalog_factories.data_models.cost.capital_cost import CapitalCost
from hub.catalog_factories.data_models.cost.envelope import Envelope
from hub.catalog_factories.data_models.cost.systems import Systems
from hub.catalog_factories.data_models.cost.hvac import Hvac
from hub.catalog_factories.data_models.cost.operational_cost import OperationalCost
from hub.catalog_factories.data_models.cost.income import Income
from hub.catalog_factories.data_models.cost.archetype import Archetype
from hub.catalog_factories.data_models.cost.content import Content
class MontrealCustomCatalog(Catalog):
def __init__(self, path):
path = str(path / 'montreal_costs.xml')
with open(path) as xml:
self._archetypes = xmltodict.parse(xml.read(), force_list='archetype')
# store the full catalog data model in self._content
self._content = Content(self._load_archetypes())
@staticmethod
def _get_threesome(entry):
_reposition = float(entry['reposition']['#text'])
_investment = float(entry['initial_investment']['#text'])
_lifetime = float(entry['lifetime_equipment']['#text'])
return _reposition, _investment, _lifetime
def _get_capital_costs(self, entry):
structural = float(entry['structural']['#text'])
sub_structural = float(entry['sub_structural']['#text'])
surface_finish = float(entry['surface_finish']['#text'])
engineer = float(entry['engineer']['#text'])
opaque_reposition, opaque_initial_investment, opaque_lifetime = \
self._get_threesome(entry['envelope']['opaque'])
transparent_reposition, transparent_initial_investment, transparent_lifetime = \
self._get_threesome(entry['envelope']['transparent'])
envelope = Envelope(opaque_reposition,
opaque_initial_investment,
opaque_lifetime,
transparent_reposition,
transparent_initial_investment,
transparent_lifetime)
heating_equipment_reposition, heating_equipment_initial_investment, heating_equipment_lifetime = \
self._get_threesome(entry['systems']['hvac']['heating_equipment_cost'])
heating_equipment_reposition = heating_equipment_reposition / 1000
heating_equipment_initial_investment = heating_equipment_initial_investment / 1000
cooling_equipment_reposition, cooling_equipment_initial_investment, cooling_equipment_lifetime = \
self._get_threesome(entry['systems']['hvac']['cooling_equipment_cost'])
cooling_equipment_reposition = cooling_equipment_reposition / 1000
cooling_equipment_initial_investment = cooling_equipment_initial_investment / 1000
general_hvac_equipment_reposition, general_hvac_equipment_initial_investment, general_hvac_equipment_lifetime = \
self._get_threesome(entry['systems']['hvac']['general_hvac_equipment_cost'])
general_hvac_equipment_reposition = general_hvac_equipment_reposition * 3600
general_hvac_equipment_initial_investment = general_hvac_equipment_initial_investment * 3600
hvac = Hvac(heating_equipment_reposition, heating_equipment_initial_investment, heating_equipment_lifetime,
cooling_equipment_reposition, cooling_equipment_initial_investment, cooling_equipment_lifetime,
general_hvac_equipment_reposition, general_hvac_equipment_initial_investment,
general_hvac_equipment_lifetime)
photovoltaic_system_reposition, photovoltaic_system_initial_investment, photovoltaic_system_lifetime = \
self._get_threesome(entry['systems']['photovoltaic_system'])
other_conditioning_systems_reposition, other_conditioning_systems_initial_investment, \
other_conditioning_systems_lifetime = self._get_threesome(entry['systems']['other_systems'])
lighting_reposition, lighting_initial_investment, lighting_lifetime = \
self._get_threesome(entry['systems']['lighting'])
systems = Systems(hvac,
photovoltaic_system_reposition,
photovoltaic_system_initial_investment,
photovoltaic_system_lifetime,
other_conditioning_systems_reposition,
other_conditioning_systems_initial_investment,
other_conditioning_systems_lifetime,
lighting_reposition,
lighting_initial_investment,
lighting_lifetime)
_capital_cost = CapitalCost(structural,
sub_structural,
envelope,
systems,
surface_finish,
engineer)
return _capital_cost
@staticmethod
def _get_operational_costs(entry):
fuel_type = entry['fuel']['@fuel_type']
fuel_fixed_operational_monthly = float(entry['fuel']['fixed']['fixed_monthly']['#text'])
fuel_fixed_operational_peak = float(entry['fuel']['fixed']['fixed_power']['#text']) / 1000
fuel_variable_operational = float(entry['fuel']['variable']['#text']) / 1000 / 3600
heating_equipment_maintenance = float(entry['maintenance']['heating_equipment']['#text']) / 1000
cooling_equipment_maintenance = float(entry['maintenance']['cooling_equipment']['#text']) / 1000
general_hvac_equipment_maintenance = float(entry['maintenance']['general_hvac_equipment']['#text']) * 3600
photovoltaic_system_maintenance = float(entry['maintenance']['photovoltaic_system']['#text'])
other_systems_maintenance = float(entry['maintenance']['other_systems']['#text'])
co2_emissions = float(entry['CO2_cost']['#text'])
_operational_cost = OperationalCost(fuel_type,
fuel_fixed_operational_monthly,
fuel_fixed_operational_peak,
fuel_variable_operational,
heating_equipment_maintenance,
cooling_equipment_maintenance,
general_hvac_equipment_maintenance,
photovoltaic_system_maintenance,
other_systems_maintenance,
co2_emissions)
return _operational_cost
def _load_archetypes(self):
_catalog_archetypes = []
archetypes = self._archetypes['archetypes']['archetype']
for archetype in archetypes:
function = archetype['@function']
municipality = archetype['@municipality']
currency = archetype['@currency']
capital_cost = self._get_capital_costs(archetype['capital_cost'])
operational_cost = self._get_operational_costs(archetype['operational_cost'])
end_of_life_cost = float(archetype['end_of_life_cost']['#text'])
construction = float(archetype['incomes']['subsidies']['construction_subsidy']['#text'])
hvac = float(archetype['incomes']['subsidies']['hvac_subsidy']['#text'])
photovoltaic_system = float(archetype['incomes']['subsidies']['photovoltaic_subsidy']['#text'])
electricity_exports = float(archetype['incomes']['energy_exports']['electricity']['#text']) / 1000 / 3600
heat_exports = float(archetype['incomes']['energy_exports']['heat']['#text']) / 1000 / 3600
co2 = float(archetype['incomes']['CO2_income']['#text'])
income = Income(construction, hvac, photovoltaic_system, electricity_exports, heat_exports, co2)
_catalog_archetypes.append(Archetype(function,
municipality,
currency,
capital_cost,
operational_cost,
end_of_life_cost,
income))
return _catalog_archetypes
def names(self, category=None):
"""
Get the catalog elements names
:parm: for costs catalog category filter does nothing as there is only one category (archetypes)
"""
_names = {'archetypes': []}
for archetype in self._content.archetypes:
_names['archetypes'].append(archetype.name)
return _names
def entries(self, category=None):
"""
Get the catalog elements
:parm: for costs catalog category filter does nothing as there is only one category (archetypes)
"""
return self._content
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
raise IndexError(f"{name} doesn't exists in the catalog")

View File

@ -0,0 +1,39 @@
"""
Cost catalog publish the life cycle cost
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Atiya atiya.atiya@mail.concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from pathlib import Path
from typing import TypeVar
from hub.catalog_factories.cost.montreal_custom_catalog import MontrealCustomCatalog
Catalog = TypeVar('Catalog')
class CostCatalogFactory:
"""
CostsCatalogFactory class
"""
def __init__(self, file_type, base_path=None):
if base_path is None:
base_path = Path(Path(__file__).parent.parent / 'data/costs')
self._catalog_type = '_' + file_type.lower()
self._path = base_path
@property
def _montreal_custom(self):
"""
Retrieve Montreal Custom catalog
"""
return MontrealCustomCatalog(self._path)
@property
def catalog(self) -> Catalog:
"""
Return a cost catalog
:return: CostCatalog
"""
return getattr(self, self._catalog_type, lambda: None)

View File

@ -16,7 +16,7 @@ class Content:
@property @property
def archetypes(self): def archetypes(self):
""" """
All archetypes in the catalogUsageZone All archetypes in the catalog
""" """
return self._archetypes return self._archetypes

View File

@ -0,0 +1,85 @@
"""
Archetype catalog Cost
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Atiya atiya.atiya@mail.concordia.ca
"""
from hub.catalog_factories.data_models.cost.capital_cost import CapitalCost
from hub.catalog_factories.data_models.cost.operational_cost import OperationalCost
from hub.catalog_factories.data_models.cost.income import Income
class Archetype:
def __init__(self, function, municipality, currency, capital_cost, operational_cost, end_of_life_cost, income):
self._function = function
self._municipality = municipality
self._currency = currency
self._capital_cost = capital_cost
self._operational_cost = operational_cost
self._end_of_life_cost = end_of_life_cost
self._income = income
@property
def name(self):
"""
Get name
:return: string
"""
return f'{self._municipality}_{self._function}'
@property
def function(self):
"""
Get function
:return: string
"""
return self._function
@property
def municipality(self):
"""
Get municipality
:return: string
"""
return self._municipality
@property
def currency(self):
"""
Get currency
:return: string
"""
return self._currency
@property
def capital_cost(self) -> CapitalCost:
"""
Get capital cost
:return: CapitalCost
"""
return self._capital_cost
@property
def operational_cost(self) -> OperationalCost:
"""
Get operational cost
:return: OperationalCost
"""
return self._operational_cost
@property
def end_of_life_cost(self):
"""
Get end of life cost in given currency
:return: float
"""
return self._end_of_life_cost
@property
def income(self) -> Income:
"""
Get income
:return: Income
"""
return self._income

View File

@ -0,0 +1,68 @@
"""
Cost catalog CapitalCost
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Atiya atiya.atiya@mail.concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from hub.catalog_factories.data_models.cost.envelope import Envelope
from hub.catalog_factories.data_models.cost.systems import Systems
class CapitalCost:
def __init__(self, structural, sub_structural, envelope, systems, surface_finish, engineer):
self._structural = structural
self._sub_structural = sub_structural
self._envelope = envelope
self._systems = systems
self._surface_finish = surface_finish
self._engineer = engineer
@property
def structural(self):
"""
Get structural cost per building volume in currency/m3
:return: float
"""
return self._structural
@property
def sub_structural(self):
"""
Get sub structural cost per building foot-print in currency/m2
:return: float
"""
return self._sub_structural
@property
def envelope(self) -> Envelope:
"""
Get envelope cost
:return: Envelope
"""
return self._envelope
@property
def systems(self) -> Systems:
"""
Get systems cost
:return: Systems
"""
return self._systems
@property
def surface_finish(self):
"""
Get surface finish cost per external surfaces areas in currency/m2
:return: float
"""
return self._surface_finish
@property
def engineer(self):
"""
Get engineer cost in %
:return: float
"""
return self._engineer

View File

@ -0,0 +1,19 @@
"""
Cost catalog content
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Atiya atiya.atiya@mail.concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
class Content:
def __init__(self, archetypes):
self._archetypes = archetypes
@property
def archetypes(self):
"""
All archetypes in the catalog
"""
return self._archetypes

View File

@ -0,0 +1,66 @@
"""
Envelope costs from Cost catalog
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Atiya atiya.atiya@mail.concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
class Envelope:
def __init__(self, opaque_reposition, opaque_initial_investment, opaque_lifetime,
transparent_reposition, transparent_initial_investment, transparent_lifetime):
self._opaque_reposition = opaque_reposition
self._opaque_initial_investment = opaque_initial_investment
self._opaque_lifetime = opaque_lifetime
self._transparent_reposition = transparent_reposition
self._transparent_initial_investment = transparent_initial_investment
self._transparent_lifetime = transparent_lifetime
@property
def opaque_reposition(self):
"""
Get reposition costs for opaque envelope per area of external opaque surfaces in currency/m2
:return: float
"""
return self._opaque_reposition
@property
def opaque_initial_investment(self):
"""
Get initial investment for opaque envelope per area of external opaque surfaces in currency/m2
:return: float
"""
return self._opaque_initial_investment
@property
def opaque_lifetime(self):
"""
Get lifetime of opaque envelope in years
:return: float
"""
return self._opaque_lifetime
@property
def transparent_reposition(self):
"""
Get reposition costs for transparent envelope per area of windows in currency/m2
:return: float
"""
return self._transparent_reposition
@property
def transparent_initial_investment(self):
"""
Get initial investment for transparent envelope per area of windows in currency/m2
:return: float
"""
return self._transparent_initial_investment
@property
def transparent_lifetime(self):
"""
Get lifetime of transparent envelope in years
:return: float
"""
return self._transparent_lifetime

View File

@ -0,0 +1,96 @@
"""
Hvac costs
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Álvarez de Uribarri pilar.monsalvete@concordia.ca
"""
class Hvac:
def __init__(self, heating_equipment_reposition, heating_equipment_initial_investment,
heating_equipment_lifetime, cooling_equipment_reposition,
cooling_equipment_initial_investment, cooling_equipment_lifetime,
general_hvac_equipment_reposition, general_hvac_equipment_initial_investment,
general_hvac_equipment_lifetime):
self._heating_equipment_reposition = heating_equipment_reposition
self._heating_equipment_initial_investment = heating_equipment_initial_investment
self._heating_equipment_lifetime = heating_equipment_lifetime
self._cooling_equipment_reposition = cooling_equipment_reposition
self._cooling_equipment_initial_investment = cooling_equipment_initial_investment
self._cooling_equipment_lifetime = cooling_equipment_lifetime
self._general_hvac_equipment_reposition = general_hvac_equipment_reposition
self._general_hvac_equipment_initial_investment = general_hvac_equipment_initial_investment
self._general_hvac_equipment_lifetime = general_hvac_equipment_lifetime
@property
def heating_equipment_reposition(self):
"""
Get reposition costs of heating equipment per peak-load in currency/W
:return: float
"""
return self._heating_equipment_reposition
@property
def heating_equipment_initial_investment(self):
"""
Get initial investment costs of heating equipment per peak-load in currency/W
:return: float
"""
return self._heating_equipment_initial_investment
@property
def heating_equipment_lifetime(self):
"""
Get lifetime of heating equipment in years
:return: float
"""
return self._heating_equipment_lifetime
@property
def cooling_equipment_reposition(self):
"""
Get reposition costs of cooling equipment per peak-load in currency/W
:return: float
"""
return self._cooling_equipment_reposition
@property
def cooling_equipment_initial_investment(self):
"""
Get initial investment costs of cooling equipment per peak-load in currency/W
:return: float
"""
return self._cooling_equipment_initial_investment
@property
def cooling_equipment_lifetime(self):
"""
Get lifetime of cooling equipment in years
:return: float
"""
return self._cooling_equipment_lifetime
@property
def general_hvac_equipment_reposition(self):
"""
Get reposition costs of general hvac equipment per peak-air-flow in currency/(m3/s)
:return: float
"""
return self._general_hvac_equipment_reposition
@property
def general_hvac_equipment_initial_investment(self):
"""
Get initial investment costs of cooling equipment per peak-air-flow in currency/(m3/s)
:return: float
"""
return self._general_hvac_equipment_initial_investment
@property
def general_hvac_equipment_lifetime(self):
"""
Get lifetime of cooling equipment in years
:return: float
"""
return self._general_hvac_equipment_lifetime

View File

@ -0,0 +1,64 @@
"""
Income from costs catalog
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Álvarez de Uribarri pilar.monsalvete@concordia.ca
"""
class Income:
def __init__(self, construction, hvac, photovoltaic_system, electricity_exports, heat_exports, co2):
self._construction = construction
self._hvac = hvac
self._photovoltaic_system = photovoltaic_system
self._electricity_exports = electricity_exports
self._heat_exports = heat_exports
self._co2 = co2
@property
def construction(self):
"""
Get construction subsidy in % of total investment construction cost
:return: float
"""
return self._construction
@property
def hvac(self):
"""
Get hvac subsidy in % of total investment HVAC cost
:return: float
"""
return self._hvac
@property
def photovoltaic_system(self):
"""
Get photovoltaic system subsidy in % of total investment photovoltaic cost
:return: float
"""
return self._photovoltaic_system
@property
def electricity_exports(self):
"""
Get electricity exports gains in currency/J
:return: float
"""
return self._construction
@property
def heat_exports(self):
"""
Get heat exports gains in currency/J
:return: float
"""
return self._heat_exports
@property
def co2(self):
"""
Get co2 income in currency/kg
:return: float
"""
return self._co2

View File

@ -0,0 +1,104 @@
"""
Cost catalog OperationalCost
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Atiya atiya.atiya@mail.concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
class OperationalCost:
def __init__(self, fuel_type, fuel_fixed_operational_monthly, fuel_fixed_operational_peak,
fuel_variable_operational, heating_equipment_maintenance, cooling_equipment_maintenance,
general_hvac_equipment_maintenance, photovoltaic_system_maintenance, other_systems_maintenance,
co2_emissions):
self._fuel_type = fuel_type
self._fuel_fixed_operational_monthly = fuel_fixed_operational_monthly
self._fuel_fixed_operational_peak = fuel_fixed_operational_peak
self._fuel_variable_operational = fuel_variable_operational
self._heating_equipment_maintenance = heating_equipment_maintenance
self._cooling_equipment_maintenance = cooling_equipment_maintenance
self._general_hvac_equipment_maintenance = general_hvac_equipment_maintenance
self._photovoltaic_system_maintenance = photovoltaic_system_maintenance
self._other_systems_maintenance = other_systems_maintenance
self._co2_emissions = co2_emissions
@property
def fuel_type(self):
"""
Get fuel type
:return: string
"""
return self._fuel_type
@property
def fuel_fixed_operational_monthly(self):
"""
Get fuel fixed operational cost in currency/month
:return: float
"""
return self._fuel_fixed_operational_monthly
@property
def fuel_fixed_operational_peak(self):
"""
Get fuel fixed operational cost per peak power in currency/W
:return: float
"""
return self._fuel_fixed_operational_peak
@property
def fuel_variable_operational(self):
"""
Get fuel variable operational cost in currency/J
:return: float
"""
return self._fuel_variable_operational
@property
def heating_equipment_maintenance(self):
"""
Get heating equipment maintenance cost per peak power in currency/W
:return: float
"""
return self._heating_equipment_maintenance
@property
def cooling_equipment_maintenance(self):
"""
Get cooling equipment maintenance cost per peak power in currency/W
:return: float
"""
return self._cooling_equipment_maintenance
@property
def general_hvac_equipment_maintenance(self):
"""
Get general hvac equipment maintenance cost per peak-air-flow in currency/(m3/s)
:return: float
"""
return self._general_hvac_equipment_maintenance
@property
def photovoltaic_system_maintenance(self):
"""
Get photovoltaic system maintenance cost per panels area in currency/m2
:return: float
"""
return self._photovoltaic_system_maintenance
@property
def other_systems_maintenance(self):
"""
Get other systems' maintenance cost per building's foot-print area in currency/m2
:return: float
"""
return self._other_systems_maintenance
@property
def co2_emissions(self):
"""
Get CO2 emissions cost in currency/kg
:return: float
"""
return self._co2_emissions

View File

@ -0,0 +1,106 @@
"""
Systems cost catalog
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Atiya atiya.atiya@mail.concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from hub.catalog_factories.data_models.cost.hvac import Hvac
class Systems:
def __init__(self, hvac, photovoltaic_system_reposition, photovoltaic_system_initial_investment,
photovoltaic_system_lifetime, other_conditioning_systems_reposition,
other_conditioning_systems_initial_investment, other_conditioning_systems_lifetime,
lighting_reposition, lighting_initial_investment, lighting_lifetime):
self._hvac = hvac
self._photovoltaic_system_reposition = photovoltaic_system_reposition
self._photovoltaic_system_initial_investment = photovoltaic_system_initial_investment
self._photovoltaic_system_lifetime = photovoltaic_system_lifetime
self._other_conditioning_systems_reposition = other_conditioning_systems_reposition
self._other_conditioning_systems_initial_investment = other_conditioning_systems_initial_investment
self._other_conditioning_systems_lifetime = other_conditioning_systems_lifetime
self._lighting_reposition = lighting_reposition
self._lighting_initial_investment = lighting_initial_investment
self._lighting_lifetime = lighting_lifetime
@property
def hvac(self) -> Hvac:
"""
Get hvac capital cost
:return: Hvac
"""
return self._hvac
@property
def photovoltaic_system_reposition(self):
"""
Get photovoltaic system reposition cost per area of panels in currency/m2
:return: float
"""
return self._photovoltaic_system_reposition
@property
def photovoltaic_system_initial_investment(self):
"""
Get photovoltaic system initial investment per area of panels in currency/m2
:return: float
"""
return self._photovoltaic_system_initial_investment
@property
def photovoltaic_system_lifetime(self):
"""
Get photovoltaic system lifetime in years
:return: float
"""
return self._photovoltaic_system_lifetime
@property
def other_conditioning_systems_reposition(self):
"""
Get other conditioning systems reposition cost per building's foot-print area in currency/m2
:return: float
"""
return self._other_conditioning_systems_reposition
@property
def other_conditioning_systems_initial_investment(self):
"""
Get other conditioning systems initial investment per building's foot-print area in currency/m2
:return: float
"""
return self._other_conditioning_systems_initial_investment
@property
def other_conditioning_systems_lifetime(self):
"""
Get other conditioning systems lifetime in years
:return: float
"""
return self._other_conditioning_systems_lifetime
@property
def lighting_reposition(self):
"""
Get lighting reposition cost per building's foot-print area in currency/m2
:return: float
"""
return self._lighting_reposition
@property
def lighting_initial_investment(self):
"""
Get lighting initial investment per building's foot-print area in currency/m2
:return: float
"""
return self._lighting_initial_investment
@property
def lighting_lifetime(self):
"""
Get lighting lifetime in years
:return: float
"""
return self._lighting_lifetime

View File

@ -5,6 +5,7 @@ Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
""" """
class InternalGain: class InternalGain:
""" """
InternalGain class InternalGain class

View File

@ -13,7 +13,7 @@ from hub.catalog_factories.data_models.usages.thermal_control import ThermalCont
class Usage: class Usage:
def __init__(self, usage, def __init__(self, name,
hours_day, hours_day,
days_year, days_year,
mechanical_air_change, mechanical_air_change,
@ -22,7 +22,7 @@ class Usage:
lighting, lighting,
appliances, appliances,
thermal_control): thermal_control):
self._usage = usage self._name = name
self._hours_day = hours_day self._hours_day = hours_day
self._days_year = days_year self._days_year = days_year
self._mechanical_air_change = mechanical_air_change self._mechanical_air_change = mechanical_air_change
@ -34,12 +34,12 @@ class Usage:
self._thermal_control = thermal_control self._thermal_control = thermal_control
@property @property
def usage(self) -> Union[None, str]: def name(self) -> Union[None, str]:
""" """
Get usage zone usage Get usage zone usage name
:return: None or str :return: None or str
""" """
return self._usage return self._name
@property @property
def hours_day(self) -> Union[None, float]: def hours_day(self) -> Union[None, float]:

View File

@ -8,8 +8,11 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
from pathlib import Path from pathlib import Path
from typing import TypeVar from typing import TypeVar
from hub.catalog_factories.greenery.greenery_catalog import GreeneryCatalog from hub.catalog_factories.greenery.greenery_catalog import GreeneryCatalog
from hub.hub_logger import logger
from hub.helpers.utils import validate_import_export_type
Catalog = TypeVar('Catalog') Catalog = TypeVar('Catalog')
class GreeneryCatalogFactory: class GreeneryCatalogFactory:
""" """
GreeneryCatalogFactory class GreeneryCatalogFactory class
@ -18,6 +21,11 @@ class GreeneryCatalogFactory:
if base_path is None: if base_path is None:
base_path = Path(Path(__file__).parent.parent / 'data/greenery') base_path = Path(Path(__file__).parent.parent / 'data/greenery')
self._catalog_type = '_' + file_type.lower() self._catalog_type = '_' + file_type.lower()
class_funcs = validate_import_export_type(GreeneryCatalogFactory)
if self._catalog_type not in class_funcs:
err_msg = f"Wrong import type. Valid functions include {class_funcs}"
logger.error(err_msg)
raise Exception(err_msg)
self._path = base_path self._path = base_path
@property @property

View File

@ -28,6 +28,7 @@ class ComnetCatalog(Catalog):
self._archetypes = self._read_archetype_file() self._archetypes = self._read_archetype_file()
self._schedules = self._read_schedules_file() self._schedules = self._read_schedules_file()
# todo: comment with @Guille, this hypotheses should go in the import factory?
sensible_convective = ch().comnet_occupancy_sensible_convective sensible_convective = ch().comnet_occupancy_sensible_convective
sensible_radiative = ch().comnet_occupancy_sensible_radiant sensible_radiative = ch().comnet_occupancy_sensible_radiant
lighting_convective = ch().comnet_lighting_convective lighting_convective = ch().comnet_lighting_convective
@ -41,7 +42,8 @@ class ComnetCatalog(Catalog):
for schedule_key in self._archetypes['schedules_key']: for schedule_key in self._archetypes['schedules_key']:
comnet_usage = schedule_key comnet_usage = schedule_key
schedule_name = self._archetypes['schedules_key'][schedule_key] schedule_name = self._archetypes['schedules_key'][schedule_key]
hours_day = self._calculate_hours_day(schedule_name) hours_day = None
days_year = None
occupancy_archetype = self._archetypes['occupancy'][comnet_usage] occupancy_archetype = self._archetypes['occupancy'][comnet_usage]
lighting_archetype = self._archetypes['lighting'][comnet_usage] lighting_archetype = self._archetypes['lighting'][comnet_usage]
appliances_archetype = self._archetypes['plug loads'][comnet_usage] appliances_archetype = self._archetypes['plug loads'][comnet_usage]
@ -86,29 +88,9 @@ class ComnetCatalog(Catalog):
self._schedules[schedule_name]['Receptacle']) self._schedules[schedule_name]['Receptacle'])
# get thermal control # get thermal control
max_heating_setpoint = cte.MIN_FLOAT thermal_control = ThermalControl(None,
min_heating_setpoint = cte.MAX_FLOAT None,
None,
for schedule in self._schedules[schedule_name]['HtgSetPt']:
if schedule.values is None:
max_heating_setpoint = None
min_heating_setpoint = None
break
if max(schedule.values) > max_heating_setpoint:
max_heating_setpoint = max(schedule.values)
if min(schedule.values) < min_heating_setpoint:
min_heating_setpoint = min(schedule.values)
min_cooling_setpoint = cte.MAX_FLOAT
for schedule in self._schedules[schedule_name]['ClgSetPt']:
if schedule.values is None:
min_cooling_setpoint = None
break
if min(schedule.values) < min_cooling_setpoint:
min_cooling_setpoint = min(schedule.values)
thermal_control = ThermalControl(max_heating_setpoint,
min_heating_setpoint,
min_cooling_setpoint,
self._schedules[schedule_name]['HVAC Avail'], self._schedules[schedule_name]['HVAC Avail'],
self._schedules[schedule_name]['HtgSetPt'], self._schedules[schedule_name]['HtgSetPt'],
self._schedules[schedule_name]['ClgSetPt'] self._schedules[schedule_name]['ClgSetPt']
@ -116,7 +98,7 @@ class ComnetCatalog(Catalog):
usages.append(Usage(comnet_usage, usages.append(Usage(comnet_usage,
hours_day, hours_day,
365, days_year,
mechanical_air_change, mechanical_air_change,
ventilation_rate, ventilation_rate,
occupancy, occupancy,
@ -202,16 +184,6 @@ class ComnetCatalog(Catalog):
'schedules_key': schedules_key 'schedules_key': schedules_key
} }
def _calculate_hours_day(self, function):
days = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY, cte.SATURDAY, cte.SUNDAY, cte.HOLIDAY]
number_of_days_per_type = [51, 50, 50, 50, 50, 52, 52, 10]
total = 0
for schedule in self._schedules[function]['HVAC Avail']:
yearly_days = number_of_days_per_type[days.index(schedule.day_types[0])]
for value in schedule.values:
total += value * yearly_days
return total / 365
def names(self, category=None): def names(self, category=None):
""" """
Get the catalog elements names Get the catalog elements names
@ -219,7 +191,7 @@ class ComnetCatalog(Catalog):
""" """
_names = {'usages': []} _names = {'usages': []}
for usage in self._content.usages: for usage in self._content.usages:
_names['usages'].append(usage.usage) _names['usages'].append(usage.name)
return _names return _names
def entries(self, category=None): def entries(self, category=None):
@ -235,6 +207,6 @@ class ComnetCatalog(Catalog):
:parm: entry name :parm: entry name
""" """
for usage in self._content.usages: for usage in self._content.usages:
if usage.usage.lower() == name.lower(): if usage.name.lower() == name.lower():
return usage return usage
raise IndexError(f"{name} doesn't exists in the catalog") raise IndexError(f"{name} doesn't exists in the catalog")

View File

@ -3,6 +3,7 @@ NRCAN usage catalog
SPDX - License - Identifier: LGPL - 3.0 - or -later SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
import json import json
@ -32,10 +33,6 @@ class NrcanCatalog(Catalog):
self._load_schedules() self._load_schedules()
self._content = Content(self._load_archetypes()) self._content = Content(self._load_archetypes())
def _calculate_hours_day(self, function):
# todo: pilar need to check how to calculate this value
return 24
@staticmethod @staticmethod
def _extract_schedule(raw): def _extract_schedule(raw):
nrcan_schedule_type = raw['category'] nrcan_schedule_type = raw['category']
@ -54,59 +51,84 @@ class NrcanCatalog(Catalog):
return Schedule(hub_type, raw['values'], data_type, time_step, time_range, day_types) return Schedule(hub_type, raw['values'], data_type, time_step, time_range, day_types)
def _load_schedules(self): def _load_schedules(self):
usage = self._metadata['nrcan']['standards']['usage'] usage = self._metadata['nrcan']
url = f'{self._base_url}{usage["schedules_location"]}' url = f'{self._base_url}{usage["schedules_location"]}'
_schedule_types = []
with urllib.request.urlopen(url) as json_file: with urllib.request.urlopen(url) as json_file:
schedules_type = json.load(json_file) schedules_type = json.load(json_file)
for schedule_type in schedules_type['tables']['schedules']['table']: for schedule_type in schedules_type['tables']['schedules']['table']:
schedule = NrcanCatalog._extract_schedule(schedule_type) schedule = NrcanCatalog._extract_schedule(schedule_type)
if schedule is not None: if schedule_type['name'] not in _schedule_types:
self._schedules[schedule_type['name']] = schedule _schedule_types.append(schedule_type['name'])
if schedule is not None:
self._schedules[schedule_type['name']] = [schedule]
else:
if schedule is not None:
_schedules = self._schedules[schedule_type['name']]
_schedules.append(schedule)
self._schedules[schedule_type['name']] = _schedules
def _get_schedule(self, name): def _get_schedules(self, name):
if name in self._schedules: if name in self._schedules:
return self._schedules[name] return self._schedules[name]
def _load_archetypes(self): def _load_archetypes(self):
usages = [] usages = []
usage = self._metadata['nrcan']['standards']['usage'] name = self._metadata['nrcan']
url = f'{self._base_url}{usage["space_types_location"]}' url = f'{self._base_url}{name["space_types_location"]}'
with urllib.request.urlopen(url) as json_file: with urllib.request.urlopen(url) as json_file:
space_types = json.load(json_file)['tables']['space_types']['table'] space_types = json.load(json_file)['tables']['space_types']['table']
space_types = [st for st in space_types if st['building_type'] == 'Space Function'] # space_types = [st for st in space_types if st['building_type'] == 'Space Function']
space_types = [st for st in space_types if st['space_type'] == 'WholeBuilding']
for space_type in space_types: for space_type in space_types:
usage_type = space_type['space_type'] # usage_type = space_type['space_type']
mechanical_air_change = space_type['ventilation_air_changes'] usage_type = space_type['building_type']
ventilation_rate = space_type['ventilation_per_area']
if ventilation_rate == 0:
ventilation_rate = space_type['ventilation_per_person']
hours_day = self._calculate_hours_day(usage_type)
days_year = 365
occupancy_schedule_name = space_type['occupancy_schedule'] occupancy_schedule_name = space_type['occupancy_schedule']
lighting_schedule_name = space_type['lighting_schedule'] lighting_schedule_name = space_type['lighting_schedule']
appliance_schedule_name = space_type['electric_equipment_schedule'] appliance_schedule_name = space_type['electric_equipment_schedule']
# thermal control hvac_schedule_name = space_type['exhaust_schedule']
if 'FAN' in hvac_schedule_name:
hvac_schedule_name = hvac_schedule_name.replace('FAN', 'Fan')
heating_setpoint_schedule_name = space_type['heating_setpoint_schedule'] heating_setpoint_schedule_name = space_type['heating_setpoint_schedule']
cooling_setpoint_schedule_name = space_type['cooling_setpoint_schedule'] cooling_setpoint_schedule_name = space_type['cooling_setpoint_schedule']
occupancy_schedule = self._get_schedule(occupancy_schedule_name) occupancy_schedule = self._get_schedules(occupancy_schedule_name)
lighting_schedule = self._get_schedule(lighting_schedule_name) lighting_schedule = self._get_schedules(lighting_schedule_name)
appliance_schedule = self._get_schedule(appliance_schedule_name) appliance_schedule = self._get_schedules(appliance_schedule_name)
heating_schedule = self._get_schedule(heating_setpoint_schedule_name) heating_schedule = self._get_schedules(heating_setpoint_schedule_name)
cooling_schedule = self._get_schedule(cooling_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'] occupancy_density = space_type['occupancy_per_area']
lighting_density = space_type['lighting_per_area']
# ACH
mechanical_air_change = space_type['ventilation_air_changes']
# cfm/ft2 to m3/m2.s
ventilation_rate = space_type['ventilation_per_area'] / (cte.METERS_TO_FEET * cte.MINUTES_TO_SECONDS)
if ventilation_rate == 0:
# cfm/person to m3/m2.s
ventilation_rate = space_type['ventilation_per_person'] / occupancy_density\
/ (cte.METERS_TO_FEET * cte.MINUTES_TO_SECONDS)
# W/sqft to W/m2
lighting_density = space_type['lighting_per_area'] * cte.METERS_TO_FEET * cte.METERS_TO_FEET
lighting_radiative_fraction = space_type['lighting_fraction_radiant'] lighting_radiative_fraction = space_type['lighting_fraction_radiant']
lighting_convective_fraction = 0
if lighting_radiative_fraction is not None: if lighting_radiative_fraction is not None:
lighting_convective_fraction = 1 - lighting_radiative_fraction lighting_convective_fraction = 1 - lighting_radiative_fraction
lighting_latent_fraction = 0 lighting_latent_fraction = 0
appliances_density = space_type['electric_equipment_per_area'] # W/sqft to W/m2
appliances_density = space_type['electric_equipment_per_area'] * cte.METERS_TO_FEET * cte.METERS_TO_FEET
appliances_radiative_fraction = space_type['electric_equipment_fraction_radiant'] appliances_radiative_fraction = space_type['electric_equipment_fraction_radiant']
if appliances_radiative_fraction is not None:
appliances_convective_fraction = 1 - appliances_radiative_fraction
appliances_latent_fraction = space_type['electric_equipment_fraction_latent'] appliances_latent_fraction = space_type['electric_equipment_fraction_latent']
appliances_convective_fraction = 0
if appliances_radiative_fraction is not None and appliances_latent_fraction is not None:
appliances_convective_fraction = 1 - appliances_radiative_fraction - appliances_latent_fraction
occupancy = Occupancy(occupancy_density, 0, 0, 0, occupancy_schedule) occupancy = Occupancy(occupancy_density,
None,
None,
None,
occupancy_schedule)
lighting = Lighting(lighting_density, lighting = Lighting(lighting_density,
lighting_convective_fraction, lighting_convective_fraction,
lighting_radiative_fraction, lighting_radiative_fraction,
@ -117,20 +139,14 @@ class NrcanCatalog(Catalog):
appliances_radiative_fraction, appliances_radiative_fraction,
appliances_latent_fraction, appliances_latent_fraction,
appliance_schedule) appliance_schedule)
if heating_schedule is not None: thermal_control = ThermalControl(None,
thermal_control = ThermalControl(max(heating_schedule.values), None,
min(heating_schedule.values), None,
min(cooling_schedule.values), hvac_availability,
None, heating_schedule,
heating_schedule, cooling_schedule)
cooling_schedule) hours_day = None
else: days_year = None
thermal_control = ThermalControl(None,
None,
None,
None,
None,
None)
usages.append(Usage(usage_type, usages.append(Usage(usage_type,
hours_day, hours_day,
days_year, days_year,
@ -149,7 +165,7 @@ class NrcanCatalog(Catalog):
""" """
_names = {'usages': []} _names = {'usages': []}
for usage in self._content.usages: for usage in self._content.usages:
_names['usages'].append(usage.usage) _names['usages'].append(usage.name)
return _names return _names
def entries(self, category=None): def entries(self, category=None):
@ -165,6 +181,6 @@ class NrcanCatalog(Catalog):
:parm: entry name :parm: entry name
""" """
for usage in self._content.usages: for usage in self._content.usages:
if usage.usage.lower() == name.lower(): if usage.name.lower() == name.lower():
return usage return usage
raise IndexError(f"{name} doesn't exists in the catalog") raise IndexError(f"{name} doesn't exists in the catalog")

View File

@ -19,6 +19,7 @@ class UsageHelper:
'Equipment': cte.APPLIANCES, 'Equipment': cte.APPLIANCES,
'Thermostat Setpoint Cooling': cte.COOLING_SET_POINT, # Compose 'Thermostat Setpoint' + 'Cooling' 'Thermostat Setpoint Cooling': cte.COOLING_SET_POINT, # Compose 'Thermostat Setpoint' + 'Cooling'
'Thermostat Setpoint Heating': cte.HEATING_SET_POINT, # Compose 'Thermostat Setpoint' + 'Heating' 'Thermostat Setpoint Heating': cte.HEATING_SET_POINT, # Compose 'Thermostat Setpoint' + 'Heating'
'Fan': cte.HVAC_AVAILABILITY
} }
_nrcan_data_type_to_hub_data_type = { _nrcan_data_type_to_hub_data_type = {
'FRACTION': cte.FRACTION, 'FRACTION': cte.FRACTION,
@ -58,31 +59,6 @@ class UsageHelper:
} }
_usage_to_hft = {
cte.RESIDENTIAL: 'residential',
cte.SINGLE_FAMILY_HOUSE: 'Single family house',
cte.MULTI_FAMILY_HOUSE: 'Multi-family house',
cte.EDUCATION: 'education',
cte.SCHOOL_WITHOUT_SHOWER: 'school without shower',
cte.SCHOOL_WITH_SHOWER: 'school with shower',
cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'retail',
cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'retail shop / refrigerated food',
cte.HOTEL: 'hotel',
cte.HOTEL_MEDIUM_CLASS: 'hotel (Medium-class)',
cte.DORMITORY: 'dormitory',
cte.INDUSTRY: 'industry',
cte.RESTAURANT: 'restaurant',
cte.HEALTH_CARE: 'health care',
cte.RETIREMENT_HOME_OR_ORPHANAGE: 'Home for the aged or orphanage',
cte.OFFICE_AND_ADMINISTRATION: 'office and administration',
cte.EVENT_LOCATION: 'event location',
cte.HALL: 'hall',
cte.SPORTS_LOCATION: 'sport location',
cte.LABOR: 'Labor',
cte.GREEN_HOUSE: 'green house',
cte.NON_HEATED: 'non-heated'
}
_comnet_days = [cte.MONDAY, _comnet_days = [cte.MONDAY,
cte.TUESDAY, cte.TUESDAY,
cte.WEDNESDAY, cte.WEDNESDAY,
@ -92,31 +68,6 @@ class UsageHelper:
cte.SUNDAY, cte.SUNDAY,
cte.HOLIDAY] cte.HOLIDAY]
_usage_to_comnet = {
cte.RESIDENTIAL: 'BA Multifamily',
cte.SINGLE_FAMILY_HOUSE: 'BA Multifamily',
cte.MULTI_FAMILY_HOUSE: 'BA Multifamily',
cte.EDUCATION: 'BA School/University',
cte.SCHOOL_WITHOUT_SHOWER: 'BA School/University',
cte.SCHOOL_WITH_SHOWER: 'BA School/University',
cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'BA Retail',
cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'BA Retail',
cte.HOTEL: 'BA Hotel',
cte.HOTEL_MEDIUM_CLASS: 'BA Hotel',
cte.DORMITORY: 'BA Dormitory',
cte.INDUSTRY: 'BA Manufacturing Facility',
cte.RESTAURANT: 'BA Dining: Family',
cte.HEALTH_CARE: 'BA Hospital',
cte.RETIREMENT_HOME_OR_ORPHANAGE: 'BA Multifamily',
cte.OFFICE_AND_ADMINISTRATION: 'BA Office',
cte.EVENT_LOCATION: 'BA Convention Center',
cte.HALL: 'BA Convention Center',
cte.SPORTS_LOCATION: 'BA Sports Arena',
cte.LABOR: 'BA Gymnasium',
cte.GREEN_HOUSE: cte.GREEN_HOUSE,
cte.NON_HEATED: cte.NON_HEATED
}
_comnet_data_type_to_hub_data_type = { _comnet_data_type_to_hub_data_type = {
'Fraction': cte.FRACTION, 'Fraction': cte.FRACTION,
'OnOff': cte.ON_OFF, 'OnOff': cte.ON_OFF,
@ -166,18 +117,6 @@ class UsageHelper:
def comnet_days(self): def comnet_days(self):
return self._comnet_days return self._comnet_days
@staticmethod
def comnet_from_hub_usage(usage):
"""
Get Comnet usage from the given internal usage key
:param usage: str
:return: str
"""
try:
return UsageHelper._usage_to_comnet[usage]
except KeyError:
sys.stderr.write('Error: keyword not found to translate from hub_usage to comnet usage.\n')
@staticmethod @staticmethod
def schedules_key(usage): def schedules_key(usage):
""" """
@ -190,15 +129,3 @@ class UsageHelper:
except KeyError: except KeyError:
sys.stderr.write('Error: Comnet keyword not found. An update of the Comnet files might have been ' sys.stderr.write('Error: Comnet keyword not found. An update of the Comnet files might have been '
'done changing the keywords.\n') 'done changing the keywords.\n')
@staticmethod
def hft_from_hub_usage(usage):
"""
Get HfT usage from the given internal usage key
:param usage: str
:return: str
"""
try:
return UsageHelper._usage_to_hft[usage]
except KeyError:
sys.stderr.write('Error: keyword not found to translate from hub_usage to hft usage.\n')

View File

@ -9,6 +9,8 @@ from pathlib import Path
from typing import TypeVar from typing import TypeVar
from hub.catalog_factories.usage.comnet_catalog import ComnetCatalog from hub.catalog_factories.usage.comnet_catalog import ComnetCatalog
from hub.catalog_factories.usage.nrcan_catalog import NrcanCatalog from hub.catalog_factories.usage.nrcan_catalog import NrcanCatalog
from hub.hub_logger import logger
from hub.helpers.utils import validate_import_export_type
Catalog = TypeVar('Catalog') Catalog = TypeVar('Catalog')
@ -17,6 +19,11 @@ class UsageCatalogFactory:
if base_path is None: if base_path is None:
base_path = Path(Path(__file__).parent.parent / 'data/usage') base_path = Path(Path(__file__).parent.parent / 'data/usage')
self._catalog_type = '_' + file_type.lower() self._catalog_type = '_' + file_type.lower()
class_funcs = validate_import_export_type(UsageCatalogFactory)
if self._catalog_type not in class_funcs:
err_msg = f"Wrong import type. Valid functions include {class_funcs}"
logger.error(err_msg)
raise Exception(err_msg)
self._path = base_path self._path = base_path
@property @property

View File

@ -9,9 +9,13 @@ from __future__ import annotations
import math import math
import sys import sys
from typing import List from typing import List
from hub.hub_logger import logger
import numpy as np import numpy as np
from trimesh import Trimesh from trimesh import Trimesh
import trimesh.intersections import trimesh.intersections
import trimesh.creation
import trimesh.geometry
from shapely.geometry.polygon import Polygon as shapley_polygon
from hub.city_model_structure.attributes.plane import Plane from hub.city_model_structure.attributes.plane import Plane
from hub.city_model_structure.attributes.point import Point from hub.city_model_structure.attributes.point import Point
@ -22,6 +26,7 @@ class Polygon:
""" """
Polygon class Polygon class
""" """
# todo: review with @Guille: Points, Coordinates, Vertices, Faces
def __init__(self, coordinates): def __init__(self, coordinates):
self._area = None self._area = None
@ -66,20 +71,6 @@ class Polygon:
""" """
return self._coordinates return self._coordinates
@staticmethod
def _module(vector):
x2 = vector[0] ** 2
y2 = vector[1] ** 2
z2 = vector[2] ** 2
return math.sqrt(x2+y2+z2)
@staticmethod
def _scalar_product(vector_0, vector_1):
x = vector_0[0] * vector_1[0]
y = vector_0[1] * vector_1[1]
z = vector_0[2] * vector_1[2]
return x+y+z
def contains_point(self, point): def contains_point(self, point):
""" """
Determines if the given point is contained by the current polygon Determines if the given point is contained by the current polygon
@ -98,9 +89,9 @@ class Polygon:
vector_1[0] = vector_1[0] - point.coordinates[0] vector_1[0] = vector_1[0] - point.coordinates[0]
vector_1[1] = vector_1[1] - point.coordinates[1] vector_1[1] = vector_1[1] - point.coordinates[1]
vector_1[2] = vector_1[2] - point.coordinates[2] vector_1[2] = vector_1[2] - point.coordinates[2]
module = Polygon._module(vector_0) * Polygon._module(vector_1) module = np.linalg.norm(vector_0) * np.linalg.norm(vector_1)
scalar_product = Polygon._scalar_product(vector_0, vector_1) scalar_product = np.dot(vector_0, vector_1)
angle = np.pi/2 angle = np.pi/2
if module != 0: if module != 0:
angle = abs(np.arcsin(scalar_product / module)) angle = abs(np.arcsin(scalar_product / module))
@ -150,69 +141,17 @@ class Polygon:
Get surface area in square meters Get surface area in square meters
:return: float :return: float
""" """
# New method to calculate area
if self._area is None: if self._area is None:
if len(self.points) < 3: self._area = 0
sys.stderr.write('Warning: the area of a line or point cannot be calculated 1. Area = 0\n') for triangle in self.triangles:
return 0 ab = np.zeros(3)
alpha = 0 ac = np.zeros(3)
vec_1 = self.points[1].coordinates - self.points[0].coordinates for i in range(0, 3):
for i in range(2, len(self.points)): ab[i] = triangle.coordinates[1][i] - triangle.coordinates[0][i]
vec_2 = self.points[i].coordinates - self.points[0].coordinates ac[i] = triangle.coordinates[2][i] - triangle.coordinates[0][i]
alpha += self._angle_between_vectors(vec_1, vec_2) self._area += np.linalg.norm(np.cross(ab, ac)) / 2
if alpha == 0:
sys.stderr.write('Warning: the area of a line or point cannot be calculated 2. Area = 0\n')
return 0
horizontal_points = self._points_rotated_to_horizontal
area = 0
for i in range(0, len(horizontal_points) - 1):
point = horizontal_points[i]
next_point = horizontal_points[i + 1]
area += (next_point[1] + point[1]) / 2 * (next_point[0] - point[0])
next_point = horizontal_points[0]
point = horizontal_points[len(horizontal_points) - 1]
area += (next_point[1] + point[1]) / 2 * (next_point[0] - point[0])
self._area = abs(area)
return self._area return self._area
@property
def _points_rotated_to_horizontal(self):
"""
polygon points rotated to horizontal
:return: [float]
"""
z_vector = [0, 0, 1]
normal_vector = self.normal
horizontal_points = []
x = normal_vector[0]
y = normal_vector[1]
if x == 0 and y == 0:
# Already horizontal
for point in self.points:
horizontal_points.append([point.coordinates[0], point.coordinates[1], 0])
else:
alpha = self._angle_between_vectors(normal_vector, z_vector)
rotation_line = np.cross(normal_vector, z_vector)
third_axis = np.cross(normal_vector, rotation_line)
w_1 = rotation_line / np.linalg.norm(rotation_line)
w_2 = normal_vector
w_3 = third_axis / np.linalg.norm(third_axis)
rotation_matrix = np.array([[1, 0, 0],
[0, np.cos(alpha), -np.sin(alpha)],
[0, np.sin(alpha), np.cos(alpha)]])
base_matrix = np.array([w_1, w_2, w_3])
rotation_base_matrix = np.matmul(base_matrix.transpose(), rotation_matrix.transpose())
rotation_base_matrix = np.matmul(rotation_base_matrix, base_matrix)
if rotation_base_matrix is None:
sys.stderr.write('Warning: rotation base matrix returned None\n')
else:
for point in self.points:
new_point = np.matmul(rotation_base_matrix, point.coordinates)
horizontal_points.append(new_point)
return horizontal_points
@property @property
def normal(self) -> np.ndarray: def normal(self) -> np.ndarray:
""" """
@ -275,283 +214,74 @@ class Polygon:
return alpha return alpha
return -alpha return -alpha
def triangulate(self) -> List[Polygon]:
"""
Triangulates a polygon following the ear clipping methodology
:return: list[triangles]
"""
# todo: review triangulate_polygon in
# https://github.com/mikedh/trimesh/blob/dad11126742e140ef46ba12f8cb8643c83356467/trimesh/creation.py#L415,
# it had a problem with a class called 'triangle', but, if solved,
# it could be a very good substitute of this method
# this method is very dirty and has an infinite loop solved with a counter!!
if self._triangles is None:
points_list = self.points_list
normal = self.normal
if np.linalg.norm(normal) == 0:
sys.stderr.write('Not able to triangulate polygon\n')
return [self]
# are points concave or convex?
total_points_list, concave_points, convex_points = self._starting_lists(points_list, normal)
# list of ears
ears = []
j = 0
while (len(concave_points) > 3 or len(convex_points) != 0) and j < 100:
j += 1
for i in range(0, len(concave_points)):
ear = self._triangle(points_list, total_points_list, concave_points[i])
rest_points = []
for points in total_points_list:
rest_points.append(list(self.coordinates[points]))
if self._is_ear(ear, rest_points):
ears.append(ear)
point_to_remove = concave_points[i]
previous_point_in_list, next_point_in_list = self._enveloping_points(point_to_remove,
total_points_list)
total_points_list.remove(point_to_remove)
concave_points.remove(point_to_remove)
# Was any of the adjacent points convex? -> check if changed status to concave
for convex_point in convex_points:
if convex_point == previous_point_in_list:
concave_points, convex_points, end_loop = self._if_concave_change_status(normal,
points_list,
convex_point,
total_points_list,
concave_points,
convex_points,
previous_point_in_list)
if end_loop:
break
continue
if convex_point == next_point_in_list:
concave_points, convex_points, end_loop = self._if_concave_change_status(normal,
points_list,
convex_point,
total_points_list,
concave_points,
convex_points,
next_point_in_list)
if end_loop:
break
continue
break
if len(total_points_list) <= 3 and len(convex_points) > 0:
sys.stderr.write('Not able to triangulate polygon\n')
return [self]
if j >= 100:
sys.stderr.write('Not able to triangulate polygon\n')
return [self]
last_ear = self._triangle(points_list, total_points_list, concave_points[1])
ears.append(last_ear)
self._triangles = ears
return self._triangles
@staticmethod @staticmethod
def _starting_lists(points_list, normal) -> [List[float], List[float], List[float]]: def triangle_mesh(vertices, normal):
""" min_x = 1e16
creates the list of vertices (points) that define the polygon (total_points_list), together with other two lists min_y = 1e16
separating points between convex and concave min_z = 1e16
:param points_list: points_list for vertex in vertices:
:param normal: normal if vertex[0] < min_x:
:return: list[point], list[point], list[point] min_x = vertex[0]
""" if vertex[1] < min_y:
concave_points = [] min_y = vertex[1]
convex_points = [] if vertex[2] < min_z:
# lists of concave and convex points min_z = vertex[2]
# case 1: first point
point = points_list[0:3]
previous_point = points_list[len(points_list) - 3:]
next_point = points_list[3:6]
index = 0
total_points_list = [index]
if Polygon._point_is_concave(normal, point, previous_point, next_point):
concave_points.append(index)
else:
convex_points.append(index)
# case 2: all points except first and last
for i in range(0, int((len(points_list) - 6) / 3)):
point = points_list[(i + 1) * 3:(i + 2) * 3]
previous_point = points_list[i * 3:(i + 1) * 3]
next_point = points_list[(i + 2) * 3:(i + 3) * 3]
index = i + 1
total_points_list.append(index)
if Polygon._point_is_concave(normal, point, previous_point, next_point):
concave_points.append(index)
else:
convex_points.append(index)
# case 3: last point
point = points_list[len(points_list) - 3:]
previous_point = points_list[len(points_list) - 6:len(points_list) - 3]
next_point = points_list[0:3]
index = int(len(points_list) / 3) - 1
total_points_list.append(index)
if Polygon._point_is_concave(normal, point, previous_point, next_point):
concave_points.append(index)
else:
convex_points.append(index)
return total_points_list, concave_points, convex_points
@staticmethod new_vertices = []
def _triangle(points_list, total_points_list, point_position) -> Polygon: for vertex in vertices:
""" vertex = [vertex[0]-min_x, vertex[1]-min_y, vertex[2]-min_z]
creates a triangular polygon out of three points new_vertices.append(vertex)
:param points_list: points_list
:param total_points_list: [point]
:param point_position: int
:return: polygon
"""
index = point_position * 3
previous_point_index, next_point_index = Polygon._enveloping_points_indices(point_position, total_points_list)
points = points_list[previous_point_index:previous_point_index + 3]
points = np.append(points, points_list[index:index + 3])
points = np.append(points, points_list[next_point_index:next_point_index + 3])
rows = points.size // 3
points = points.reshape(rows, 3)
triangle = Polygon(points)
return triangle
@staticmethod transformation_matrix = trimesh.geometry.plane_transform(origin=new_vertices[0], normal=normal)
def _enveloping_points_indices(point_position, total_points_list):
"""
due to the fact that the lists are not circular, a method to find the previous and next points
of an specific one is needed
:param point_position: int
:param total_points_list: [point]
:return: int, int
"""
previous_point_index = None
next_point_index = None
if point_position == total_points_list[0]:
previous_point_index = total_points_list[len(total_points_list) - 1] * 3
next_point_index = total_points_list[1] * 3
if point_position == total_points_list[len(total_points_list) - 1]:
previous_point_index = total_points_list[len(total_points_list) - 2] * 3
next_point_index = total_points_list[0] * 3
for i in range(1, len(total_points_list) - 1):
if point_position == total_points_list[i]:
previous_point_index = total_points_list[i - 1] * 3
next_point_index = total_points_list[i + 1] * 3
return previous_point_index, next_point_index
@staticmethod coordinates = []
def _enveloping_points(point_to_remove, total_points_list): for vertex in vertices:
""" transformed_vertex = [vertex[0]-min_x, vertex[1]-min_y, vertex[2]-min_z, 1]
due to the fact that the lists are not circular, a method to find the previous and next points transformed_vertex = np.dot(transformation_matrix, transformed_vertex)
of an specific one is needed coordinate = [transformed_vertex[0], transformed_vertex[1]]
:param point_to_remove: point coordinates.append(coordinate)
:param total_points_list: [point]
:return: point, point
"""
index = total_points_list.index(point_to_remove)
if index == 0:
previous_point_in_list = total_points_list[len(total_points_list) - 1]
next_point_in_list = total_points_list[1]
elif index == len(total_points_list) - 1:
previous_point_in_list = total_points_list[len(total_points_list) - 2]
next_point_in_list = total_points_list[0]
else:
previous_point_in_list = total_points_list[index - 1]
next_point_in_list = total_points_list[index + 1]
return previous_point_in_list, next_point_in_list
@staticmethod polygon = shapley_polygon(coordinates)
def _is_ear(ear, points) -> bool:
""" try:
finds whether a triangle is an ear of the polygon vertices_2d, faces = trimesh.creation.triangulate_polygon(polygon, engine='triangle')
:param ear: polygon mesh = Trimesh(vertices=vertices, faces=faces)
:param points: [point]
:return: boolean # check orientation
""" normal_sum = 0
area_ear = ear.area
for point in points:
area_points = 0
point_is_not_vertex = True
for i in range(0, 3): for i in range(0, 3):
if abs(np.linalg.norm(point) - np.linalg.norm(ear.coordinates[i])) < 0.0001: normal_sum += normal[i] + mesh.face_normals[0][i]
point_is_not_vertex = False
break
if point_is_not_vertex:
for i in range(0, 3):
if i != 2:
new_points = ear.coordinates[i][:]
new_points = np.append(new_points, ear.coordinates[i + 1][:])
new_points = np.append(new_points, point[:])
else:
new_points = ear.coordinates[i][:]
new_points = np.append(new_points, point[:])
new_points = np.append(new_points, ear.coordinates[0][:])
rows = new_points.size // 3
new_points = new_points.reshape(rows, 3)
new_triangle = Polygon(new_points)
area_points += new_triangle.area
if abs(area_points - area_ear) < 1e-6:
# point_inside_ear = True
return False
return True
@staticmethod if abs(normal_sum) <= 1E-10:
def _if_concave_change_status(normal, points_list, convex_point, total_points_list, new_faces = []
concave_points, convex_points, point_in_list) -> [List[float], List[float], bool]: for face in faces:
""" new_face = []
checks whether an convex specific point change its status to concave after removing one ear in the polygon for i in range(0, len(face)):
returning the new convex and concave points lists together with a flag advising that the list of total points new_face.append(face[len(face)-i-1])
already 3 and, therefore, the triangulation must be finished. new_faces.append(new_face)
:param normal: normal mesh = Trimesh(vertices=vertices, faces=new_faces)
:param points_list: points_list
:param convex_point: int
:param total_points_list: [point]
:param concave_points: [point]
:param convex_points: [point]
:param point_in_list: int
:return: list[points], list[points], boolean
"""
end_loop = False
point = points_list[point_in_list * 3:(point_in_list + 1) * 3]
pointer = total_points_list.index(point_in_list) - 1
if pointer < 0:
pointer = len(total_points_list) - 1
previous_point = points_list[total_points_list[pointer] * 3:total_points_list[pointer] * 3 + 3]
pointer = total_points_list.index(point_in_list) + 1
if pointer >= len(total_points_list):
pointer = 0
next_point = points_list[total_points_list[pointer] * 3:total_points_list[pointer] * 3 + 3]
if Polygon._point_is_concave(normal, point, previous_point, next_point):
if concave_points[0] > convex_point:
concave_points.insert(0, convex_point)
elif concave_points[len(concave_points) - 1] < convex_point:
concave_points.append(convex_point)
else:
for point_index in range(0, len(concave_points) - 1):
if concave_points[point_index] < convex_point < concave_points[point_index + 1]:
concave_points.insert(point_index + 1, convex_point)
convex_points.remove(convex_point)
end_loop = True
return concave_points, convex_points, end_loop
@staticmethod return mesh
def _point_is_concave(normal, point, previous_point, next_point) -> bool:
""" except ValueError:
returns whether a point is concave logger.error(f'Not able to triangulate polygon\n')
:param normal: normal sys.stderr.write(f'Not able to triangulate polygon\n')
:param point: point _vertices = [[0, 0, 0], [0, 0, 1], [0, 1, 0]]
:param previous_point: point _faces = [[0, 1, 2]]
:param next_point: point return Trimesh(vertices=_vertices, faces=_faces)
:return: boolean
""" @property
is_concave = False def triangles(self) -> List[Polygon]:
accepted_error = 0.1 if self._triangles is None:
points = np.append(previous_point, point) self._triangles = []
points = np.append(points, next_point) _mesh = self.triangle_mesh(self.coordinates, self.normal)
rows = points.size // 3 for face in _mesh.faces:
points = points.reshape(rows, 3) points = []
triangle = Polygon(points) for vertex in face:
error_sum = 0 points.append(self.coordinates[vertex])
for i in range(0, len(normal)): polygon = Polygon(points)
error_sum += triangle.normal[i] - normal[i] self._triangles.append(polygon)
if np.abs(error_sum) < accepted_error: return self._triangles
is_concave = True
return is_concave
@staticmethod @staticmethod
def _angle_between_vectors(vec_1, vec_2): def _angle_between_vectors(vec_1, vec_2):
@ -652,12 +382,12 @@ class Polygon:
@property @property
def vertices(self) -> np.ndarray: def vertices(self) -> np.ndarray:
""" """
Get polyhedron vertices Get polygon vertices
:return: np.ndarray(int) :return: np.ndarray(int)
""" """
if self._vertices is None: if self._vertices is None:
vertices, self._vertices = [], [] vertices, self._vertices = [], []
_ = [vertices.extend(s.coordinates) for s in self.triangulate()] _ = [vertices.extend(s.coordinates) for s in self.triangles]
for vertex_1 in vertices: for vertex_1 in vertices:
found = False found = False
for vertex_2 in self._vertices: for vertex_2 in self._vertices:
@ -677,17 +407,17 @@ class Polygon:
@property @property
def faces(self) -> List[List[int]]: def faces(self) -> List[List[int]]:
""" """
Get polyhedron triangular faces Get polygon triangular faces
:return: [face] :return: [face]
""" """
if self._faces is None: if self._faces is None:
self._faces = [] self._faces = []
for polygon in self.triangulate(): for polygon in self.triangles:
face = [] face = []
points = polygon.coordinates points = polygon.coordinates
if len(points) != 3: if len(points) != 3:
sub_polygons = polygon.triangulate() sub_polygons = polygon.triangles
# todo: I modified this! To be checked @Guille # todo: I modified this! To be checked @Guille
if len(sub_polygons) >= 1: if len(sub_polygons) >= 1:
for sub_polygon in sub_polygons: for sub_polygon in sub_polygons:

View File

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

View File

@ -6,8 +6,10 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
import sys
from typing import List, Union from typing import List, Union
import numpy as np import numpy as np
from hub.hub_logger import logger
import hub.helpers.constants as cte import hub.helpers.constants as cte
from hub.city_model_structure.building_demand.surface import Surface from hub.city_model_structure.building_demand.surface import Surface
from hub.city_model_structure.city_object import CityObject from hub.city_model_structure.city_object import CityObject
@ -34,7 +36,7 @@ class Building(CityObject):
self._roof_type = None self._roof_type = None
self._internal_zones = None self._internal_zones = None
self._shell = None self._shell = None
self._human_readable_name = None self._alias = None
self._type = 'building' self._type = 'building'
self._heating = dict() self._heating = dict()
self._cooling = dict() self._cooling = dict()
@ -46,20 +48,31 @@ class Building(CityObject):
self._roofs = [] self._roofs = []
self._walls = [] self._walls = []
self._internal_walls = [] self._internal_walls = []
self._ground_walls = []
self._attic_floors = []
self._interior_slabs = []
for surface_id, surface in enumerate(self.surfaces): for surface_id, surface in enumerate(self.surfaces):
self._min_x = min(self._min_x, surface.lower_corner[0]) self._min_x = min(self._min_x, surface.lower_corner[0])
self._min_y = min(self._min_y, surface.lower_corner[1]) self._min_y = min(self._min_y, surface.lower_corner[1])
self._min_z = min(self._min_z, surface.lower_corner[2]) self._min_z = min(self._min_z, surface.lower_corner[2])
surface.id = surface_id surface.id = surface_id
# todo: consider all type of surfaces, not only these four
if surface.type == cte.GROUND: if surface.type == cte.GROUND:
self._grounds.append(surface) self._grounds.append(surface)
elif surface.type == cte.WALL: elif surface.type == cte.WALL:
self._walls.append(surface) self._walls.append(surface)
elif surface.type == cte.ROOF: elif surface.type == cte.ROOF:
self._roofs.append(surface) self._roofs.append(surface)
else: elif surface.type == cte.INTERIOR_WALL:
self._internal_walls.append(surface) self._internal_walls.append(surface)
elif surface.type == cte.GROUND_WALL:
self._ground_walls.append(surface)
elif surface.type == cte.ATTIC_FLOOR:
self._attic_floors.append(surface)
elif surface.type == cte.INTERIOR_SLAB:
self._interior_slabs.append(surface)
else:
logger.error(f'Building {self.name} [alias {self.alias}] has an unexpected surface type {surface.type}.\n')
sys.stderr.write(f'Building {self.name} [alias {self.alias}] has an unexpected surface type {surface.type}.\n')
@property @property
def shell(self) -> Polyhedron: def shell(self) -> Polyhedron:
@ -397,23 +410,34 @@ class Building(CityObject):
if self.internal_zones is None: if self.internal_zones is None:
return False return False
for internal_zone in self.internal_zones: for internal_zone in self.internal_zones:
if internal_zone.usage_zones is not None: if internal_zone.usages is not None:
for usage_zone in internal_zone.usage_zones: for usage in internal_zone.usages:
if usage_zone.thermal_control is not None: if usage.thermal_control is not None:
return True return True
return False return False
@property @property
def human_readable_name(self): def alias(self):
""" """
Get the human-readable name for the building Get the alias name for the building
:return: str :return: str
""" """
return self._human_readable_name return self._alias
@human_readable_name.setter @alias.setter
def human_readable_name(self, value): def alias(self, value):
""" """
Set the human-readable name for the building Set the alias name for the building
""" """
self._human_readable_name = value self._alias = value
@property
def usages_percentage(self):
"""
Get the usages and percentages for the building
"""
_usage = ''
for internal_zone in self.internal_zones:
for usage in internal_zone.usages:
_usage = f'{_usage}{usage.name}_{usage.percentage} '
return _usage.rstrip()

View File

@ -7,7 +7,7 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
import uuid import uuid
from typing import Union, List from typing import Union, List
from hub.city_model_structure.building_demand.usage_zone import UsageZone from hub.city_model_structure.building_demand.usage import Usage
from hub.city_model_structure.building_demand.thermal_zone import ThermalZone from hub.city_model_structure.building_demand.thermal_zone import ThermalZone
from hub.city_model_structure.attributes.polyhedron import Polyhedron from hub.city_model_structure.attributes.polyhedron import Polyhedron
from hub.city_model_structure.energy_systems.hvac_system import HvacSystem from hub.city_model_structure.energy_systems.hvac_system import HvacSystem
@ -24,7 +24,7 @@ class InternalZone:
self._volume = None self._volume = None
self._area = area self._area = area
self._thermal_zones = None self._thermal_zones = None
self._usage_zones = None self._usages = None
self._hvac_system = None self._hvac_system = None
@property @property
@ -75,20 +75,20 @@ class InternalZone:
return self._area return self._area
@property @property
def usage_zones(self) -> [UsageZone]: def usages(self) -> [Usage]:
""" """
Get internal zone usage zones Get internal zone usage zones
:return: [UsageZone] :return: [UsageZone]
""" """
return self._usage_zones return self._usages
@usage_zones.setter @usages.setter
def usage_zones(self, value): def usages(self, value):
""" """
Set internal zone usage zones Set internal zone usage zones
:param value: [UsageZone] :param value: [UsageZone]
""" """
self._usage_zones = value self._usages = value
@property @property
def hvac_system(self) -> Union[None, HvacSystem]: def hvac_system(self) -> Union[None, HvacSystem]:

View File

@ -6,7 +6,6 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
from typing import Union, List from typing import Union, List
from hub.city_model_structure.attributes.schedule import Schedule from hub.city_model_structure.attributes.schedule import Schedule
from hub.city_model_structure.building_demand.occupant import Occupant
class Occupancy: class Occupancy:
@ -106,19 +105,3 @@ class Occupancy:
:param value: [Schedule] :param value: [Schedule]
""" """
self._occupancy_schedules = value self._occupancy_schedules = value
@property
def occupants(self) -> Union[None, List[Occupant]]:
"""
Get list of occupants
:return: None or List of Occupant
"""
return self._occupants
@occupants.setter
def occupants(self, value):
"""
Set list of occupants
:param value: [Occupant]
"""
self._occupants = value

View File

@ -1,147 +0,0 @@
"""
Occupant module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Sanam Dabirian sanam.dabirian@mail.concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import calendar as cal
class Occupant:
"""
Occupant class
"""
def __init__(self):
"""
Constructor
"""
self._heat_dissipation = None
self._occupancy_rate = None
self._occupant_type = None
self._arrival_time = None
self._departure_time = None
self._break_time = None
self._day_of_week = None
self._pd_of_meetings_duration = None
@property
def heat_dissipation(self):
"""
Get heat dissipation of occupants in W/person
:return: float
"""
return self._heat_dissipation
@heat_dissipation.setter
def heat_dissipation(self, value):
"""
Set heat dissipation of occupants in W/person
:param value: float
"""
self._heat_dissipation = float(value)
@property
def occupancy_rate(self):
"""
Get rate of schedules
:return: float
"""
return self._occupancy_rate
@occupancy_rate.setter
def occupancy_rate(self, value):
"""
Set rate of schedules
:param value: float
"""
self._occupancy_rate = float(value)
@property
def occupant_type(self):
"""
Get type of schedules
:return: str
"""
return self._occupant_type
@occupant_type.setter
def occupant_type(self, value):
"""
Set type of schedules
:param value: float
"""
self._occupant_type = float(value)
@property
def arrival_time(self):
"""
Get the arrival time of the occupant (for office building) in UTC with format YYYYMMDD HH:mm:ss
:return: time
"""
return self._arrival_time
@arrival_time.setter
def arrival_time(self, value):
"""
Set the arrival time of the occupant (for office building) in UTC with format YYYYMMDD HH:mm:ss
:param value: time
"""
self._arrival_time = value
@property
def departure_time(self):
"""
Get the departure time of the occupant (for office building) in UTC with format YYYYMMDD HH:mm:ss
:return: time
"""
return self._departure_time
@departure_time.setter
def departure_time(self, value):
"""
Set the departure time of the occupant (for office building) in UTC with format YYYYMMDD HH:mm:ss
:param value: str
"""
self._departure_time = value
@property
def break_time(self):
"""
Get the lunch or break time of the occupant (for office building) in UTC with format ????
:return: break time
"""
# todo @Sanam: define this format, is it the starting time? is it a list with both, starting and ending time?
return self._break_time
@property
def day_of_week(self):
"""
Get the day of the week (MON, TUE, WED, THU, FRI, SAT, SUN)
:return: str
"""
# todo @Sanam: is this a property or should it be a function
# to get the day of the week of an specific day of the year?
return self._day_of_week
@property
def pd_of_meetings_duration(self):
"""
Get the probability distribution of the meeting duration
:return: ??
"""
# todo @Sanam: what format are you expecting here??
return self._pd_of_meetings_duration
@pd_of_meetings_duration.setter
def pd_of_meetings_duration(self, value):
"""
Get the probability distribution of the meeting duration
:param value: ??
:return:
"""
# todo @Sanam: what format are you expecting here??
self._pd_of_meetings_duration = value

View File

@ -72,14 +72,6 @@ class Surface:
if value is not None: if value is not None:
self._id = str(value) self._id = str(value)
# todo: implement share surfaces
@property
def share_surfaces(self):
"""
Raises not implemented error
"""
raise NotImplementedError
def _max_coord(self, axis): def _max_coord(self, axis):
if axis == 'x': if axis == 'x':
axis = 0 axis = 0
@ -163,11 +155,11 @@ class Surface:
@property @property
def type(self): def type(self):
""" """
Get surface type Ground, Wall or Roof Get surface type Ground, Ground wall, Wall, Attic floor, Interior slab, Interior wall, Roof or Virtual internal
If the geometrical LoD is lower than 4,
the surfaces' types are not defined in the importer and can only be Ground, Wall or Roof
:return: str :return: str
""" """
# todo: there are more types: internal wall, internal floor... this method must be redefined
if self._type is None: if self._type is None:
grad = np.rad2deg(self.inclination) grad = np.rad2deg(self.inclination)
if grad >= 170: if grad >= 170:
@ -304,7 +296,7 @@ class Surface:
:return: Surface, Surface, Any :return: Surface, Surface, Any
""" """
# todo: check return types # todo: check return types
# todo: recheck this method for LoD3 (windows) # recheck this method for LoD3 (windows)
origin = Point([0, 0, z]) origin = Point([0, 0, z])
normal = np.array([0, 0, 1]) normal = np.array([0, 0, 1])
plane = Plane(normal=normal, origin=origin) plane = Plane(normal=normal, origin=origin)

View File

@ -26,7 +26,8 @@ class ThermalZone:
""" """
ThermalZone class ThermalZone class
""" """
def __init__(self, thermal_boundaries, parent_internal_zone, volume, footprint_area, usage=None):
def __init__(self, thermal_boundaries, parent_internal_zone, volume, footprint_area, usage_name=None):
self._id = None self._id = None
self._parent_internal_zone = parent_internal_zone self._parent_internal_zone = parent_internal_zone
self._footprint_area = footprint_area self._footprint_area = footprint_area
@ -40,9 +41,9 @@ class ThermalZone:
self._ordinate_number = None self._ordinate_number = None
self._view_factors_matrix = None self._view_factors_matrix = None
self._total_floor_area = None self._total_floor_area = None
self._usage = usage self._usage_name = usage_name
self._usage_from_parent = False self._usage_from_parent = False
if usage is None: if usage_name is None:
self._usage_from_parent = True self._usage_from_parent = True
self._hours_day = None self._hours_day = None
self._days_year = None self._days_year = None
@ -55,21 +56,21 @@ class ThermalZone:
self._usages = None self._usages = None
@property @property
def usage_zones(self): def usages(self):
# example 70-office_30-residential # example 70-office_30-residential
if self._usage_from_parent: if self._usage_from_parent:
self._usages = copy.deepcopy(self._parent_internal_zone.usage_zones) self._usages = copy.deepcopy(self._parent_internal_zone.usages)
else: else:
values = self._usage.split('_') values = self._usage_name.split('_')
usages = [] usages = []
for value in values: for value in values:
usages.append(value.split('-')) usages.append(value.split('-'))
self._usages = [] self._usages = []
for parent_usage in self._parent_internal_zone.usage_zones: for parent_usage in self._parent_internal_zone.usages:
for value in usages: for value in usages:
if parent_usage.usage == value[1]: if parent_usage.name == value[1]:
new_usage = copy.deepcopy(parent_usage) new_usage = copy.deepcopy(parent_usage)
new_usage.percentage = float(value[0])/100 new_usage.percentage = float(value[0]) / 100
self._usages.append(new_usage) self._usages.append(new_usage)
return self._usages return self._usages
@ -224,19 +225,19 @@ class ThermalZone:
self._view_factors_matrix = value self._view_factors_matrix = value
@property @property
def usage(self) -> Union[None, str]: def usage_name(self) -> Union[None, str]:
""" """
Get thermal zone usage Get thermal zone usage name
:return: None or str :return: None or str
""" """
if self._usage_from_parent: if self._usage_from_parent:
if self._parent_internal_zone.usage_zones is None: if self._parent_internal_zone.usages is None:
return None return None
self._usage = '' self._usage_name = ''
for usage_zone in self._parent_internal_zone.usage_zones: for usage in self._parent_internal_zone.usages:
self._usage += str(round(usage_zone.percentage * 100)) + '-' + usage_zone.usage + '_' self._usage_name += str(round(usage.percentage * 100)) + '-' + usage.name + '_'
self._usage = self._usage[:-1] self._usage_name = self._usage_name[:-1]
return self._usage return self._usage_name
@staticmethod @staticmethod
def _get_schedule_of_day(requested_day_type, schedules): def _get_schedule_of_day(requested_day_type, schedules):
@ -252,12 +253,12 @@ class ThermalZone:
Get thermal zone usage hours per day Get thermal zone usage hours per day
:return: None or float :return: None or float
""" """
if self.usage_zones is None: if self.usages is None:
return None return None
if self._hours_day is None: if self._hours_day is None:
self._hours_day = 0 self._hours_day = 0
for usage_zone in self.usage_zones: for usage in self.usages:
self._hours_day += usage_zone.percentage * usage_zone.hours_day self._hours_day += usage.percentage * usage.hours_day
return self._hours_day return self._hours_day
@property @property
@ -266,12 +267,12 @@ class ThermalZone:
Get thermal zone usage days per year Get thermal zone usage days per year
:return: None or float :return: None or float
""" """
if self.usage_zones is None: if self.usages is None:
return None return None
if self._days_year is None: if self._days_year is None:
self._days_year = 0 self._days_year = 0
for usage_zone in self.usage_zones: for usage in self.usages:
self._days_year += usage_zone.percentage * usage_zone.days_year self._days_year += usage.percentage * usage.days_year
return self._days_year return self._days_year
@property @property
@ -280,14 +281,14 @@ class ThermalZone:
Get thermal zone mechanical air change in air change per hour (ACH) Get thermal zone mechanical air change in air change per hour (ACH)
:return: None or float :return: None or float
""" """
if self.usage_zones is None: if self.usages is None:
return None return None
if self._mechanical_air_change is None: if self._mechanical_air_change is None:
self._mechanical_air_change = 0 self._mechanical_air_change = 0
for usage_zone in self.usage_zones: for usage in self.usages:
if usage_zone.mechanical_air_change is None: if usage.mechanical_air_change is None:
return None return None
self._mechanical_air_change += usage_zone.percentage * usage_zone.mechanical_air_change self._mechanical_air_change += usage.percentage * usage.mechanical_air_change
return self._mechanical_air_change return self._mechanical_air_change
@property @property
@ -296,7 +297,7 @@ class ThermalZone:
Get occupancy in the thermal zone Get occupancy in the thermal zone
:return: None or Occupancy :return: None or Occupancy
""" """
if self.usage_zones is None: if self.usages is None:
return None return None
if self._occupancy is None: if self._occupancy is None:
@ -305,29 +306,35 @@ class ThermalZone:
_convective_part = 0 _convective_part = 0
_radiative_part = 0 _radiative_part = 0
_latent_part = 0 _latent_part = 0
for usage_zone in self.usage_zones: for usage in self.usages:
if usage_zone.occupancy is None: if usage.occupancy is None:
return None return None
_occupancy_density += usage_zone.percentage * usage_zone.occupancy.occupancy_density _occupancy_density += usage.percentage * usage.occupancy.occupancy_density
if usage_zone.occupancy.sensible_convective_internal_gain is not None: if usage.occupancy.sensible_convective_internal_gain is not None:
_convective_part += usage_zone.percentage * usage_zone.occupancy.sensible_convective_internal_gain _convective_part += usage.percentage * usage.occupancy.sensible_convective_internal_gain
_radiative_part += usage_zone.percentage * usage_zone.occupancy.sensible_radiative_internal_gain _radiative_part += usage.percentage * usage.occupancy.sensible_radiative_internal_gain
_latent_part += usage_zone.percentage * usage_zone.occupancy.latent_internal_gain _latent_part += usage.percentage * usage.occupancy.latent_internal_gain
self._occupancy.occupancy_density = _occupancy_density self._occupancy.occupancy_density = _occupancy_density
self._occupancy.sensible_convective_internal_gain = _convective_part self._occupancy.sensible_convective_internal_gain = _convective_part
self._occupancy.sensible_radiative_internal_gain = _radiative_part self._occupancy.sensible_radiative_internal_gain = _radiative_part
self._occupancy.latent_internal_gain = _latent_part self._occupancy.latent_internal_gain = _latent_part
_occupancy_reference = self.usage_zones[0].occupancy _occupancy_reference = self.usages[0].occupancy
if _occupancy_reference.occupancy_schedules is not None: if _occupancy_reference.occupancy_schedules is not None:
_schedules = [] _schedules = []
for i_schedule in range(0, len(_occupancy_reference.occupancy_schedules)): for i_schedule in range(0, len(_occupancy_reference.occupancy_schedules)):
schedule = copy.deepcopy(_occupancy_reference.occupancy_schedules[i_schedule]) schedule = Schedule()
schedule.type = _occupancy_reference.occupancy_schedules[i_schedule].type
schedule.day_types = _occupancy_reference.occupancy_schedules[i_schedule].day_types
schedule.data_type = _occupancy_reference.occupancy_schedules[i_schedule].data_type
schedule.time_step = _occupancy_reference.occupancy_schedules[i_schedule].time_step
schedule.time_range = _occupancy_reference.occupancy_schedules[i_schedule].time_range
new_values = [] new_values = []
for i_value in range(0, len(_occupancy_reference.occupancy_schedules[i_schedule].values)): for i_value in range(0, len(_occupancy_reference.occupancy_schedules[i_schedule].values)):
_new_value = 0 _new_value = 0
for usage_zone in self.usage_zones: for usage in self.usages:
_new_value += usage_zone.percentage * usage_zone.occupancy.occupancy_schedules[i_schedule].values[i_value] _new_value += usage.percentage * usage.occupancy.occupancy_schedules[i_schedule].values[i_value]
new_values.append(_new_value) new_values.append(_new_value)
schedule.values = new_values schedule.values = new_values
_schedules.append(schedule) _schedules.append(schedule)
@ -340,7 +347,7 @@ class ThermalZone:
Get lighting information Get lighting information
:return: None or Lighting :return: None or Lighting
""" """
if self.usage_zones is None: if self.usages is None:
return None return None
if self._lighting is None: if self._lighting is None:
@ -349,17 +356,17 @@ class ThermalZone:
_convective_part = 0 _convective_part = 0
_radiative_part = 0 _radiative_part = 0
_latent_part = 0 _latent_part = 0
for usage_zone in self.usage_zones: for usage in self.usages:
if usage_zone.lighting is None: if usage.lighting is None:
return None return None
_lighting_density += usage_zone.percentage * usage_zone.lighting.density _lighting_density += usage.percentage * usage.lighting.density
if usage_zone.lighting.convective_fraction is not None: if usage.lighting.convective_fraction is not None:
_convective_part += usage_zone.percentage * usage_zone.lighting.density \ _convective_part += usage.percentage * usage.lighting.density \
* usage_zone.lighting.convective_fraction * usage.lighting.convective_fraction
_radiative_part += usage_zone.percentage * usage_zone.lighting.density \ _radiative_part += usage.percentage * usage.lighting.density \
* usage_zone.lighting.radiative_fraction * usage.lighting.radiative_fraction
_latent_part += usage_zone.percentage * usage_zone.lighting.density \ _latent_part += usage.percentage * usage.lighting.density \
* usage_zone.lighting.latent_fraction * usage.lighting.latent_fraction
self._lighting.density = _lighting_density self._lighting.density = _lighting_density
if _lighting_density > 0: if _lighting_density > 0:
self._lighting.convective_fraction = _convective_part / _lighting_density self._lighting.convective_fraction = _convective_part / _lighting_density
@ -370,16 +377,22 @@ class ThermalZone:
self._lighting.radiative_fraction = 0 self._lighting.radiative_fraction = 0
self._lighting.latent_fraction = 0 self._lighting.latent_fraction = 0
_lighting_reference = self.usage_zones[0].lighting _lighting_reference = self.usages[0].lighting
if _lighting_reference.schedules is not None: if _lighting_reference.schedules is not None:
_schedules = [] _schedules = []
for i_schedule in range(0, len(_lighting_reference.schedules)): for i_schedule in range(0, len(_lighting_reference.schedules)):
schedule = copy.deepcopy(_lighting_reference.schedules[i_schedule]) schedule = Schedule()
schedule.type = _lighting_reference.schedules[i_schedule].type
schedule.day_types = _lighting_reference.schedules[i_schedule].day_types
schedule.data_type = _lighting_reference.schedules[i_schedule].data_type
schedule.time_step = _lighting_reference.schedules[i_schedule].time_step
schedule.time_range = _lighting_reference.schedules[i_schedule].time_range
new_values = [] new_values = []
for i_value in range(0, len(_lighting_reference.schedules[i_schedule].values)): for i_value in range(0, len(_lighting_reference.schedules[i_schedule].values)):
_new_value = 0 _new_value = 0
for usage_zone in self.usage_zones: for usage in self.usages:
_new_value += usage_zone.percentage * usage_zone.lighting.schedules[i_schedule].values[i_value] _new_value += usage.percentage * usage.lighting.schedules[i_schedule].values[i_value]
new_values.append(_new_value) new_values.append(_new_value)
schedule.values = new_values schedule.values = new_values
_schedules.append(schedule) _schedules.append(schedule)
@ -392,7 +405,7 @@ class ThermalZone:
Get appliances information Get appliances information
:return: None or Appliances :return: None or Appliances
""" """
if self.usage_zones is None: if self.usages is None:
return None return None
if self._appliances is None: if self._appliances is None:
@ -401,17 +414,17 @@ class ThermalZone:
_convective_part = 0 _convective_part = 0
_radiative_part = 0 _radiative_part = 0
_latent_part = 0 _latent_part = 0
for usage_zone in self.usage_zones: for usage in self.usages:
if usage_zone.appliances is None: if usage.appliances is None:
return None return None
_appliances_density += usage_zone.percentage * usage_zone.appliances.density _appliances_density += usage.percentage * usage.appliances.density
if usage_zone.appliances.convective_fraction is not None: if usage.appliances.convective_fraction is not None:
_convective_part += usage_zone.percentage * usage_zone.appliances.density \ _convective_part += usage.percentage * usage.appliances.density \
* usage_zone.appliances.convective_fraction * usage.appliances.convective_fraction
_radiative_part += usage_zone.percentage * usage_zone.appliances.density \ _radiative_part += usage.percentage * usage.appliances.density \
* usage_zone.appliances.radiative_fraction * usage.appliances.radiative_fraction
_latent_part += usage_zone.percentage * usage_zone.appliances.density \ _latent_part += usage.percentage * usage.appliances.density \
* usage_zone.appliances.latent_fraction * usage.appliances.latent_fraction
self._appliances.density = _appliances_density self._appliances.density = _appliances_density
if _appliances_density > 0: if _appliances_density > 0:
self._appliances.convective_fraction = _convective_part / _appliances_density self._appliances.convective_fraction = _convective_part / _appliances_density
@ -422,16 +435,22 @@ class ThermalZone:
self._appliances.radiative_fraction = 0 self._appliances.radiative_fraction = 0
self._appliances.latent_fraction = 0 self._appliances.latent_fraction = 0
_appliances_reference = self.usage_zones[0].appliances _appliances_reference = self.usages[0].appliances
if _appliances_reference.schedules is not None: if _appliances_reference.schedules is not None:
_schedules = [] _schedules = []
for i_schedule in range(0, len(_appliances_reference.schedules)): for i_schedule in range(0, len(_appliances_reference.schedules)):
schedule = copy.deepcopy(_appliances_reference.schedules[i_schedule]) schedule = Schedule()
schedule.type = _appliances_reference.schedules[i_schedule].type
schedule.day_types = _appliances_reference.schedules[i_schedule].day_types
schedule.data_type = _appliances_reference.schedules[i_schedule].data_type
schedule.time_step = _appliances_reference.schedules[i_schedule].time_step
schedule.time_range = _appliances_reference.schedules[i_schedule].time_range
new_values = [] new_values = []
for i_value in range(0, len(_appliances_reference.schedules[i_schedule].values)): for i_value in range(0, len(_appliances_reference.schedules[i_schedule].values)):
_new_value = 0 _new_value = 0
for usage_zone in self.usage_zones: for usage in self.usages:
_new_value += usage_zone.percentage * usage_zone.appliances.schedules[i_schedule].values[i_value] _new_value += usage.percentage * usage.appliances.schedules[i_schedule].values[i_value]
new_values.append(_new_value) new_values.append(_new_value)
schedule.values = new_values schedule.values = new_values
_schedules.append(schedule) _schedules.append(schedule)
@ -444,7 +463,7 @@ class ThermalZone:
Calculates and returns the list of all internal gains defined Calculates and returns the list of all internal gains defined
:return: [InternalGain] :return: [InternalGain]
""" """
if self.usage_zones is None: if self.usages is None:
return None return None
if self._internal_gains is None: if self._internal_gains is None:
@ -462,17 +481,17 @@ class ThermalZone:
_base_schedule.data_type = cte.ANY_NUMBER _base_schedule.data_type = cte.ANY_NUMBER
_schedules_defined = True _schedules_defined = True
values = numpy.zeros([24, 8]) values = numpy.zeros([24, 8])
for usage_zone in self.usage_zones: for usage in self.usages:
for internal_gain in usage_zone.internal_gains: for internal_gain in usage.internal_gains:
_average_internal_gain += internal_gain.average_internal_gain * usage_zone.percentage _average_internal_gain += internal_gain.average_internal_gain * usage.percentage
_convective_fraction += internal_gain.average_internal_gain * usage_zone.percentage \ _convective_fraction += internal_gain.average_internal_gain * usage.percentage \
* internal_gain.convective_fraction * internal_gain.convective_fraction
_radiative_fraction += internal_gain.average_internal_gain * usage_zone.percentage \ _radiative_fraction += internal_gain.average_internal_gain * usage.percentage \
* internal_gain.radiative_fraction * internal_gain.radiative_fraction
_latent_fraction += internal_gain.average_internal_gain * usage_zone.percentage \ _latent_fraction += internal_gain.average_internal_gain * usage.percentage \
* internal_gain.latent_fraction * internal_gain.latent_fraction
for usage_zone in self.usage_zones: for usage in self.usages:
for internal_gain in usage_zone.internal_gains: for internal_gain in usage.internal_gains:
if internal_gain.schedules is None: if internal_gain.schedules is None:
_schedules_defined = False _schedules_defined = False
break break
@ -481,7 +500,7 @@ class ThermalZone:
break break
for day, _schedule in enumerate(internal_gain.schedules): for day, _schedule in enumerate(internal_gain.schedules):
for v, value in enumerate(_schedule.values): for v, value in enumerate(_schedule.values):
values[v, day] += value * usage_zone.percentage values[v, day] += value * usage.percentage
if _schedules_defined: if _schedules_defined:
_schedules = [] _schedules = []
@ -506,7 +525,7 @@ class ThermalZone:
Get thermal control of this thermal zone Get thermal control of this thermal zone
:return: None or ThermalControl :return: None or ThermalControl
""" """
if self.usage_zones is None: if self.usages is None:
return None return None
if self._thermal_control is None: if self._thermal_control is None:
@ -514,15 +533,15 @@ class ThermalZone:
_mean_heating_set_point = 0 _mean_heating_set_point = 0
_heating_set_back = 0 _heating_set_back = 0
_mean_cooling_set_point = 0 _mean_cooling_set_point = 0
for usage_zone in self.usage_zones: for usage in self.usages:
_mean_heating_set_point += usage_zone.percentage * usage_zone.thermal_control.mean_heating_set_point _mean_heating_set_point += usage.percentage * usage.thermal_control.mean_heating_set_point
_heating_set_back += usage_zone.percentage * usage_zone.thermal_control.heating_set_back _heating_set_back += usage.percentage * usage.thermal_control.heating_set_back
_mean_cooling_set_point += usage_zone.percentage * usage_zone.thermal_control.mean_cooling_set_point _mean_cooling_set_point += usage.percentage * usage.thermal_control.mean_cooling_set_point
self._thermal_control.mean_heating_set_point = _mean_heating_set_point self._thermal_control.mean_heating_set_point = _mean_heating_set_point
self._thermal_control.heating_set_back = _heating_set_back self._thermal_control.heating_set_back = _heating_set_back
self._thermal_control.mean_cooling_set_point = _mean_cooling_set_point self._thermal_control.mean_cooling_set_point = _mean_cooling_set_point
_thermal_control_reference = self.usage_zones[0].thermal_control _thermal_control_reference = self.usages[0].thermal_control
_types_reference = [] _types_reference = []
if _thermal_control_reference.hvac_availability_schedules is not None: if _thermal_control_reference.hvac_availability_schedules is not None:
_types_reference.append([cte.HVAC_AVAILABILITY, _thermal_control_reference.hvac_availability_schedules]) _types_reference.append([cte.HVAC_AVAILABILITY, _thermal_control_reference.hvac_availability_schedules])
@ -535,20 +554,26 @@ class ThermalZone:
_schedules = [] _schedules = []
_schedule_type = _types_reference[i_type][1] _schedule_type = _types_reference[i_type][1]
for i_schedule in range(0, len(_schedule_type)): for i_schedule in range(0, len(_schedule_type)):
schedule = copy.deepcopy(_schedule_type[i_schedule]) schedule = Schedule()
schedule.type = _schedule_type[i_schedule].type
schedule.day_types = _schedule_type[i_schedule].day_types
schedule.data_type = _schedule_type[i_schedule].data_type
schedule.time_step = _schedule_type[i_schedule].time_step
schedule.time_range = _schedule_type[i_schedule].time_range
new_values = [] new_values = []
for i_value in range(0, len(_schedule_type[i_schedule].values)): for i_value in range(0, len(_schedule_type[i_schedule].values)):
_new_value = 0 _new_value = 0
for usage_zone in self.usage_zones: for usage in self.usages:
if _types_reference[i_type][0] == cte.HVAC_AVAILABILITY: if _types_reference[i_type][0] == cte.HVAC_AVAILABILITY:
_new_value += usage_zone.percentage * \ _new_value += usage.percentage * \
usage_zone.thermal_control.hvac_availability_schedules[i_schedule].values[i_value] usage.thermal_control.hvac_availability_schedules[i_schedule].values[i_value]
elif _types_reference[i_type][0] == cte.HEATING_SET_POINT: elif _types_reference[i_type][0] == cte.HEATING_SET_POINT:
_new_value += usage_zone.percentage * \ _new_value += usage.percentage * \
usage_zone.thermal_control.heating_set_point_schedules[i_schedule].values[i_value] usage.thermal_control.heating_set_point_schedules[i_schedule].values[i_value]
elif _types_reference[i_type][0] == cte.COOLING_SET_POINT: elif _types_reference[i_type][0] == cte.COOLING_SET_POINT:
_new_value += usage_zone.percentage * \ _new_value += usage.percentage * \
usage_zone.thermal_control.cooling_set_point_schedules[i_schedule].values[i_value] usage.thermal_control.cooling_set_point_schedules[i_schedule].values[i_value]
new_values.append(_new_value) new_values.append(_new_value)
schedule.values = new_values schedule.values = new_values
_schedules.append(schedule) _schedules.append(schedule)

View File

@ -0,0 +1,246 @@
"""
Usage module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Code contributors: Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
import uuid
from typing import Union, List
import hub.helpers.constants as cte
from hub.city_model_structure.building_demand.occupancy import Occupancy
from hub.city_model_structure.building_demand.lighting import Lighting
from hub.city_model_structure.building_demand.appliances import Appliances
from hub.city_model_structure.building_demand.thermal_control import ThermalControl
from hub.city_model_structure.building_demand.internal_gain import InternalGain
class Usage:
"""
Usage class
"""
def __init__(self):
self._id = None
self._name = None
self._percentage = None
self._internal_gains = None
self._hours_day = None
self._days_year = None
self._mechanical_air_change = None
self._occupancy = None
self._lighting = None
self._appliances = None
self._thermal_control = None
@property
def id(self):
"""
Get usage zone id, a universally unique identifier randomly generated
:return: str
"""
if self._id is None:
self._id = uuid.uuid4()
return self._id
@property
def name(self) -> Union[None, str]:
"""
Get usage zone usage
:return: None or str
"""
return self._name
@name.setter
def name(self, value):
"""
Set usage zone usage
:param value: str
"""
if value is not None:
self._name = str(value)
@property
def percentage(self):
"""
Get usage zone percentage in range[0,1]
:return: float
"""
return self._percentage
@percentage.setter
def percentage(self, value):
"""
Set usage zone percentage in range[0,1]
:param value: float
"""
if value is not None:
self._percentage = float(value)
@property
def internal_gains(self) -> List[InternalGain]:
"""
Calculates and returns the list of all internal gains defined
:return: InternalGains
"""
if self._internal_gains is None:
if self.occupancy is not None:
if self.occupancy.latent_internal_gain is not None:
_internal_gain = InternalGain()
_internal_gain.type = cte.OCCUPANCY
_total_heat_gain = (self.occupancy.sensible_convective_internal_gain
+ self.occupancy.sensible_radiative_internal_gain
+ self.occupancy.latent_internal_gain)
_internal_gain.average_internal_gain = _total_heat_gain
_internal_gain.latent_fraction = self.occupancy.latent_internal_gain / _total_heat_gain
_internal_gain.radiative_fraction = self.occupancy.sensible_radiative_internal_gain / _total_heat_gain
_internal_gain.convective_fraction = self.occupancy.sensible_convective_internal_gain / _total_heat_gain
_internal_gain.schedules = self.occupancy.occupancy_schedules
self._internal_gains = [_internal_gain]
if self.lighting is not None:
_internal_gain = InternalGain()
_internal_gain.type = cte.LIGHTING
_internal_gain.average_internal_gain = self.lighting.density
_internal_gain.latent_fraction = self.lighting.latent_fraction
_internal_gain.radiative_fraction = self.lighting.radiative_fraction
_internal_gain.convective_fraction = self.lighting.convective_fraction
_internal_gain.schedules = self.lighting.schedules
if self._internal_gains is not None:
self._internal_gains.append(_internal_gain)
else:
self._internal_gains = [_internal_gain]
if self.appliances is not None:
_internal_gain = InternalGain()
_internal_gain.type = cte.APPLIANCES
_internal_gain.average_internal_gain = self.appliances.density
_internal_gain.latent_fraction = self.appliances.latent_fraction
_internal_gain.radiative_fraction = self.appliances.radiative_fraction
_internal_gain.convective_fraction = self.appliances.convective_fraction
_internal_gain.schedules = self.appliances.schedules
if self._internal_gains is not None:
self._internal_gains.append(_internal_gain)
else:
self._internal_gains = [_internal_gain]
return self._internal_gains
@internal_gains.setter
def internal_gains(self, value):
"""
Set usage zone internal gains
:param value: [InternalGain]
"""
self._internal_gains = value
@property
def hours_day(self) -> Union[None, float]:
"""
Get usage zone usage hours per day
:return: None or float
"""
return self._hours_day
@hours_day.setter
def hours_day(self, value):
"""
Set usage zone usage hours per day
:param value: float
"""
if value is not None:
self._hours_day = float(value)
@property
def days_year(self) -> Union[None, float]:
"""
Get usage zone usage days per year
:return: None or float
"""
return self._days_year
@days_year.setter
def days_year(self, value):
"""
Set usage zone usage days per year
:param value: float
"""
if value is not None:
self._days_year = float(value)
@property
def mechanical_air_change(self) -> Union[None, float]:
"""
Get usage zone mechanical air change in air change per hour (ACH)
:return: None or float
"""
return self._mechanical_air_change
@mechanical_air_change.setter
def mechanical_air_change(self, value):
"""
Set usage zone mechanical air change in air change per hour (ACH)
:param value: float
"""
if value is not None:
self._mechanical_air_change = float(value)
@property
def occupancy(self) -> Union[None, Occupancy]:
"""
Get occupancy in the usage zone
:return: None or Occupancy
"""
return self._occupancy
@occupancy.setter
def occupancy(self, value):
"""
Set occupancy in the usage zone
:param value: Occupancy
"""
self._occupancy = value
@property
def lighting(self) -> Union[None, Lighting]:
"""
Get lighting information
:return: None or Lighting
"""
return self._lighting
@lighting.setter
def lighting(self, value):
"""
Set lighting information
:param value: Lighting
"""
self._lighting = value
@property
def appliances(self) -> Union[None, Appliances]:
"""
Get appliances information
:return: None or Appliances
"""
return self._appliances
@appliances.setter
def appliances(self, value):
"""
Set appliances information
:param value: Appliances
"""
self._appliances = value
@property
def thermal_control(self) -> Union[None, ThermalControl]:
"""
Get thermal control of this thermal zone
:return: None or ThermalControl
"""
return self._thermal_control
@thermal_control.setter
def thermal_control(self, value):
"""
Set thermal control for this thermal zone
:param value: ThermalControl
"""
self._thermal_control = value

View File

@ -26,7 +26,6 @@ class UsageZone:
self._internal_gains = None self._internal_gains = None
self._hours_day = None self._hours_day = None
self._days_year = None self._days_year = None
# self._electrical_app_average_consumption_sqm_year = None
self._mechanical_air_change = None self._mechanical_air_change = None
self._occupancy = None self._occupancy = None
self._lighting = None self._lighting = None

View File

@ -17,8 +17,8 @@ class BusSystem(CityObject):
""" """
BusSystem(CityObject) class BusSystem(CityObject) class
""" """
def __init__(self, name, surfaces, city_lower_corner): def __init__(self, name, surfaces):
super().__init__(name, surfaces, city_lower_corner) super().__init__(name, surfaces)
self._bus_routes = None self._bus_routes = None
self._bus_network = None self._bus_network = None
self._buses = None self._buses = None

View File

@ -6,6 +6,8 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
Code contributors: Peter Yefi peteryefi@gmail.com Code contributors: Peter Yefi peteryefi@gmail.com
""" """
from __future__ import annotations from __future__ import annotations
import bz2
import sys import sys
import pickle import pickle
import math import math
@ -23,7 +25,6 @@ from hub.city_model_structure.iot.station import Station
from hub.city_model_structure.level_of_detail import LevelOfDetail from hub.city_model_structure.level_of_detail import LevelOfDetail
from hub.city_model_structure.machine import Machine from hub.city_model_structure.machine import Machine
from hub.city_model_structure.parts_consisting_building import PartsConsistingBuilding from hub.city_model_structure.parts_consisting_building import PartsConsistingBuilding
from hub.city_model_structure.subway_entrance import SubwayEntrance
from hub.helpers.geometry_helper import GeometryHelper from hub.helpers.geometry_helper import GeometryHelper
from hub.helpers.location import Location from hub.helpers.location import Location
from hub.city_model_structure.energy_system import EnergySystem from hub.city_model_structure.energy_system import EnergySystem
@ -40,10 +41,7 @@ class City:
self._lower_corner = lower_corner self._lower_corner = lower_corner
self._upper_corner = upper_corner self._upper_corner = upper_corner
self._buildings = None self._buildings = None
self._subway_entrances = None
self._srs_name = srs_name self._srs_name = srs_name
self._geometry = GeometryHelper()
# todo: right now extracted at city level, in the future should be extracted also at building level if exist
self._location = None self._location = None
self._country_code = None self._country_code = None
self._climate_reference_city = None self._climate_reference_city = None
@ -102,13 +100,19 @@ class City:
""" """
return self._get_location().country return self._get_location().country
@property
def location(self):
return self._get_location().city
@property @property
def name(self): def name(self):
""" """
Get city name Get city name
:return: str :return: str
""" """
return self._get_location().city if self._name is None:
return self._get_location().city
return self._name
@property @property
def climate_reference_city(self) -> Union[None, str]: def climate_reference_city(self) -> Union[None, str]:
@ -158,9 +162,6 @@ class City:
if self.buildings is not None: if self.buildings is not None:
for building in self.buildings: for building in self.buildings:
self._city_objects.append(building) self._city_objects.append(building)
if self.subway_entrances is not None:
for subway_entrance in self.subway_entrances:
self._city_objects.append(subway_entrance)
if self.energy_systems is not None: if self.energy_systems is not None:
for energy_system in self.energy_systems: for energy_system in self.energy_systems:
self._city_objects.append(energy_system) self._city_objects.append(energy_system)
@ -174,14 +175,6 @@ class City:
""" """
return self._buildings return self._buildings
@property
def subway_entrances(self) -> Union[List[SubwayEntrance], None]:
"""
Get the subway entrances belonging to the city
:return: a list of subway entrances objects or none
"""
return self._subway_entrances
@property @property
def lower_corner(self) -> List[float]: def lower_corner(self) -> List[float]:
""" """
@ -219,10 +212,6 @@ class City:
if self._buildings is None: if self._buildings is None:
self._buildings = [] self._buildings = []
self._buildings.append(new_city_object) self._buildings.append(new_city_object)
elif new_city_object.type == 'subway_entrance':
if self._subway_entrances is None:
self._subway_entrances = []
self._subway_entrances.append(new_city_object)
elif new_city_object.type == 'energy_system': elif new_city_object.type == 'energy_system':
if self._energy_systems is None: if self._energy_systems is None:
self._energy_systems = [] self._energy_systems = []
@ -280,6 +269,15 @@ class City:
with open(city_filename, 'wb') as file: with open(city_filename, 'wb') as file:
pickle.dump(self, file) pickle.dump(self, file)
def save_compressed(self, city_filename):
"""
Save a city into the given filename
:param city_filename: destination city filename
:return: None
"""
with bz2.BZ2File(city_filename, 'wb') as f:
pickle.dump(self, f)
def region(self, center, radius) -> City: def region(self, center, radius) -> City:
""" """
Get a region from the city Get a region from the city

View File

@ -224,5 +224,3 @@ class CityObject:
:param value: [Sensor] :param value: [Sensor]
""" """
self._sensors = value self._sensors = value

View File

@ -43,4 +43,3 @@ class Fuel:
:return: str :return: str
""" """
return self._unit return self._unit

View File

@ -5,6 +5,7 @@ Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
""" """
class SensorMeasure: class SensorMeasure:
def __init__(self, latitude, longitude, utc_timestamp, value): def __init__(self, latitude, longitude, utc_timestamp, value):
self._latitude = latitude self._latitude = latitude

View File

@ -7,6 +7,7 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
from enum import Enum from enum import Enum
class SensorType(Enum): class SensorType(Enum):
HUMIDITY = 0 HUMIDITY = 0
TEMPERATURE = 1 TEMPERATURE = 1

View File

@ -26,7 +26,7 @@ class Station:
return self._id return self._id
@property @property
def _mobile(self): def mobile(self):
""" """
Get if the station is mobile or not Get if the station is mobile or not
:return: bool :return: bool

View File

@ -1,21 +0,0 @@
"""
LifeCycleAssessment retrieve the specific Life Cycle Assessment module for the given region
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Atiya atiya.atiya@mail.concordia.ca
"""
from hub.city_model_structure.machine import Machine
class LcaCalculations:
"""
LCA Calculations class
"""
def emission_disposal_machines(self, ):
return Machine.work_efficiency * Machine.energy_consumption_rate * Machine.carbon_emission_factor
def emission_transportation(self, weight, distance ):
return weight * distance * Machine.energy_consumption_rate * Machine.carbon_emission_factor

View File

@ -14,6 +14,8 @@ class LevelOfDetail:
self._geometry = None self._geometry = None
self._construction = None self._construction = None
self._usage = None self._usage = None
self._weather = None
self._surface_radiation = None
@property @property
def geometry(self): def geometry(self):
@ -59,3 +61,33 @@ class LevelOfDetail:
Set the city minimal usage level of detail, 1 or 2 Set the city minimal usage level of detail, 1 or 2
""" """
self._usage = value self._usage = value
@property
def weather(self):
"""
Get the city minimal weather level of detail, 0 (yearly), 1 (monthly), 2 (hourly)
:return: int
"""
return self._weather
@weather.setter
def weather(self, value):
"""
Set the city minimal weather level of detail, 0 (yearly), 1 (monthly), 2 (hourly)
"""
self._usage = value
@property
def surface_radiation(self):
"""
Get the city minimal surface radiation level of detail, 0 (yearly), 1 (monthly), 2 (hourly)
:return: int
"""
return self._surface_radiation
@surface_radiation.setter
def surface_radiation(self, value):
"""
Set the city minimal surface radiation level of detail, 0 (yearly), 1 (monthly), 2 (hourly)
"""
self._surface_radiation = value

View File

@ -11,8 +11,8 @@ class Machine:
Machine class Machine class
""" """
def __init__(self, machine_id, name, work_efficiency, work_efficiency_unit, energy_consumption_rate, energy_consumption_unit, def __init__(self, machine_id, name, work_efficiency, work_efficiency_unit, energy_consumption_rate,
carbon_emission_factor, carbon_emission_unit): energy_consumption_unit, carbon_emission_factor, carbon_emission_unit):
self._machine_id = machine_id self._machine_id = machine_id
self._name = name self._name = name
self._work_efficiency = work_efficiency self._work_efficiency = work_efficiency
@ -85,4 +85,3 @@ class Machine:
:return: str :return: str
""" """
return self._carbon_emission_unit return self._carbon_emission_unit

View File

@ -18,7 +18,7 @@ class Network(CityObject):
Generic network class to be used as base for the network models Generic network class to be used as base for the network models
""" """
def __init__(self, name, edges=None, nodes=None): def __init__(self, name, edges=None, nodes=None):
super().__init__(name, 0, [], None) super().__init__(name, 0)
if nodes is None: if nodes is None:
nodes = [] nodes = []
if edges is None: if edges is None:

View File

@ -1,45 +0,0 @@
"""
Subway entrance module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from hub.city_model_structure.city_object import CityObject
class SubwayEntrance(CityObject):
"""
SubwayEntrance(CityObject) class
"""
def __init__(self, name, latitude, longitude):
super().__init__(name, 0, [])
self._name = name
self._latitude = latitude
self._longitude = longitude
self._type = 'subway_entrance'
@property
def latitude(self):
# todo: to be defined the spacial point and the units
"""
Get latitude
:return: float
"""
return self._latitude
@property
def longitude(self):
# todo: to be defined the spacial point and the units
"""
Get longitude
:return: float
"""
return self._longitude
@property
def name(self):
"""
Get name
:return: str
"""
return self._name

View File

@ -10,7 +10,8 @@ class Vehicle:
Vehicle class Vehicle class
""" """
def __init__(self, vehicle_id, name, fuel_consumption_rate, fuel_consumption_unit, carbon_emission_factor, carbon_emission_factor_unit): def __init__(self, vehicle_id, name, fuel_consumption_rate, fuel_consumption_unit, carbon_emission_factor,
carbon_emission_factor_unit):
self._vehicle_id = vehicle_id self._vehicle_id = vehicle_id
self._name = name self._name = name
self._fuel_consumption_rate = fuel_consumption_rate self._fuel_consumption_rate = fuel_consumption_rate
@ -59,10 +60,9 @@ class Vehicle:
return self._carbon_emission_factor return self._carbon_emission_factor
@property @property
def carbon_emission_unit(self) -> str: def carbon_emission_factor_unit(self) -> str:
""" """
Get carbon emission units Get carbon emission units
:return: str :return: str
""" """
return self._carbon_emission_unit return self._carbon_emission_factor_unit

View File

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8" ?>
<nrcan base_url_archetypes="https://raw.githubusercontent.com/canmet-energy/necb-2011-baselines/master/output/"
base_url_construction="https://raw.githubusercontent.com/NREL/openstudio-standards/master/lib/openstudio-standards/standards/necb/">
<standards_per_period>
<standard period_of_construction="1000_1979">
<constructions_location>BTAPPRE1980/data/surface_thermal_transmittance.json</constructions_location>
<g_value_location>BTAPPRE1980/data/window_characteristics.json</g_value_location>
</standard>
<standard period_of_construction="1980_2010">
<constructions_location>BTAP1980TO2010/data/surface_thermal_transmittance.json</constructions_location>
<g_value_location>BTAP1980TO2010/data/window_characteristics.json</g_value_location>
</standard>
<standard period_of_construction="2011_2016">
<constructions_location>NECB2011/data/surface_thermal_transmittance.json</constructions_location>
<g_value_location>BTAP1980TO2010/data/window_characteristics.json</g_value_location>
</standard>
<standard period_of_construction="2017_2019">
<constructions_location>NECB2017/data/surface_thermal_transmittance.json</constructions_location>
<g_value_location>BTAP1980TO2010/data/window_characteristics.json</g_value_location>
</standard>
<standard period_of_construction="2020_3000">
<constructions_location>NECB2020/data/surface_thermal_transmittance.json</constructions_location>
<g_value_location>BTAP1980TO2010/data/window_characteristics.json</g_value_location>
</standard>
</standards_per_period>
<standards_per_function>
<standard function="FullServiceRestaurant">
<file_location>FullServiceRestaurant/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/8414706d-3ba9-4d70-ad3c-4db62d865e1b-os-report.html</file_location>
</standard>
<standard function="HighriseApartment">
<file_location>HighriseApartment/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/83ab3764-046e-48a8-85cd-a3c0ac761efa-os-report.html</file_location>
</standard>
<standard function="Hospital">
<file_location>Hospital/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/210dac7e-2d51-40a9-bc78-ad0bc1c57a89-os-report.html</file_location>
</standard>
<standard function="LargeHotel">
<file_location>LargeHotel/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/d0185276-7fe0-4da9-bb5d-8c8a7c13c405-os-report.html</file_location>
</standard>
<standard function="LargeOffice">
<file_location>LargeOffice/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/2da33707-50a7-4554-91ed-c5fdbc1ce3b9-os-report.html</file_location>
</standard>
<standard function="MediumOffice">
<file_location>MediumOffice/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/65d97bf8-8749-410b-b53d-5a9c60e0227c-os-report.html</file_location>
</standard>
<standard function="MidriseApartment">
<file_location>MidriseApartment/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/19518153-9c28-4e40-8bbd-98ef949c1bdb-os-report.html</file_location>
</standard>
<standard function="Outpatient">
<file_location>Outpatient/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/deab93c7-d086-432d-bb90-33c8c4e1fab3-os-report.html</file_location>
</standard>
<standard function="PrimarySchool">
<file_location>PrimarySchool/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/87f45397-5ef4-4df9-be41-d33c4b6d2fb7-os-report.html</file_location>
</standard>
<standard function="QuickServiceRestaurant">
<file_location>QuickServiceRestaurant/CAN_PQ_Montreal.Intl.AP.716270_CWEC/ 0bc55858-a81b-4d07-9923-1d84e8a23194-os-report.html</file_location>
</standard>
<standard function="RetailStandalone">
<file_location>RetailStandalone/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/a3643bcb-0eea-47d4-b6b9-253ed188ec0c-os-report.html</file_location>
</standard>
<standard function="RetailStripmall">
<file_location>RetailStripmall/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/ebaf5a16-00af-49de-9672-6b373fc825be-os-report.html</file_location>
</standard>
<standard function="SecondarySchool">
<file_location>SecondarySchool/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/3a4f105f-93ed-4b8b-9eb3-c8ca40c5de6e-os-report.html</file_location>
</standard>
<standard function="SmallHotel">
<file_location>SmallHotel/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/dff0a3fc-d9e5-4866-9e6a-dee9a0da60b2-os-report.html</file_location>
</standard>
<standard function="SmallOffice">
<file_location>SmallOffice/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/a9a3669d-beb8-4951-aa11-c27dbc61a344-os-report.html</file_location>
</standard>
<standard function="Warehouse">
<file_location>Warehouse/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/569ec649-8017-4a3c-bd0a-337eba3ec488-os-report.html</file_location>
</standard>
</standards_per_function>
</nrcan>

View File

@ -0,0 +1,89 @@
<archetypes>
<archetype function="residential" municipality="montreal" currency="CAD">
<capital_cost>
<structural cost_unit="currency/m3"> 56 </structural>
<sub_structural cost_unit="currency/m2"> 9.8 </sub_structural>
<envelope>
<opaque>
<reposition cost_unit="currency/m2"> 43.4 </reposition>
<initial_investment cost_unit="currency/m2"> 36 </initial_investment>
<lifetime_equipment lifetime="years"> 50 </lifetime_equipment>
</opaque>
<transparent>
<reposition cost_unit="currency/m2"> 78 </reposition>
<initial_investment cost_unit="currency/m2"> 984.5 </initial_investment>
<lifetime_equipment lifetime="years"> 20 </lifetime_equipment>
</transparent>
</envelope>
<systems>
<hvac>
<heating_equipment_cost>
<initial_investment cost_unit="currency/kW"> 363.5 </initial_investment>
<reposition cost_unit="currency/kW"> 363.5 </reposition>
<lifetime_equipment lifetime="years"> 15 </lifetime_equipment>
</heating_equipment_cost>
<cooling_equipment_cost>
<initial_investment cost_unit="currency/kW"> 363.5 </initial_investment>
<reposition cost_unit="currency/kW"> 363.5 </reposition>
<lifetime_equipment lifetime="years"> 15 </lifetime_equipment>
</cooling_equipment_cost>
<general_hvac_equipment_cost>
<initial_investment cost_unit="currency/(m3/h)"> 363.5 </initial_investment>
<reposition cost_unit="currency/(m3/h)"> 363.5 </reposition>
<lifetime_equipment lifetime="years"> 15 </lifetime_equipment>
</general_hvac_equipment_cost>
</hvac>
<photovoltaic_system>
<initial_investment cost_unit="currency/m2"> 17 </initial_investment>
<reposition cost_unit="currency/m2"> 17 </reposition>
<lifetime_equipment lifetime="years"> 15 </lifetime_equipment>
</photovoltaic_system>
<other_systems>
<initial_investment cost_unit="currency/m2"> 365 </initial_investment>
<reposition cost_unit="currency/m2"> 365 </reposition>
<lifetime_equipment lifetime="years"> 15 </lifetime_equipment>
</other_systems>
<lighting>
<initial_investment cost_unit="currency/m2"> 365 </initial_investment>
<reposition cost_unit="currency/m2"> 365 </reposition>
<lifetime_equipment lifetime="years"> 15 </lifetime_equipment>
</lighting>
</systems>
<surface_finish cost_unit="currency/m2"> 88 </surface_finish>
<engineer cost_unit="%"> 2.5 </engineer>
</capital_cost>
<operational_cost>
<fuel fuel_type="electricity">
<fixed>
<fixed_monthly cost_unit="currency/month"> 0 </fixed_monthly>
<fixed_power cost_unit="currency/kW"> 0 </fixed_power>
</fixed>
<variable cost_unit="currency/kWh"> 5.6 </variable>
</fuel>
<maintenance>
<heating_equipment cost_unit="currency/kW"> 40 </heating_equipment>
<cooling_equipment cost_unit="currency/kW"> 40 </cooling_equipment>
<general_hvac_equipment cost_unit="currency/(m3/h)"> 0.05 </general_hvac_equipment>
<photovoltaic_system cost_unit="currency/m2"> 1 </photovoltaic_system>
<other_systems cost_unit="currency/m2"> 4.6 </other_systems>
</maintenance>
<CO2_cost cost_unit="currency/kgCO2"> 30 </CO2_cost>
</operational_cost>
<end_of_life_cost cost_unit="currency/m2"> 6.3 </end_of_life_cost>
<incomes>
<subsidies>
<construction_subsidy cost_unit="%"> 2 </construction_subsidy>
<hvac_subsidy cost_unit="%"> 1.5 </hvac_subsidy>
<photovoltaic_subsidy cost_unit="%"> 3.6 </photovoltaic_subsidy>
</subsidies>
<energy_exports>
<electricity cost_unit="currency/kWh"> 0 </electricity>
<heat cost_unit="currency/kWh"> 0 </heat>
</energy_exports>
<tax_reductions>
<reductions_taxes cost_unit="%"> 2 </reductions_taxes>
</tax_reductions>
<CO2_income cost_unit="currency/kgCO2exported"> 0 </CO2_income>
</incomes>
</archetype>
</archetypes>

View File

@ -1,35 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<buildingUsageLibrary>
<name>Building Usage Library Reduced</name>
<description>Library created by Sanam from HOT200 and ecobee</description>
<source>https://www.engineeringtoolbox.com/metabolic-heat-persons-d_706.html</source>
<zoneUsageType>
<id>residential</id>
<description>All residential buildings</description>
<occupancy>
<occupancyDensity>0.03</occupancyDensity>
<usageDaysPerYear>365</usageDaysPerYear>
<usageHoursPerDay>14</usageHoursPerDay>
<internGains>
<description>Persons and home appliances</description>
<averageInternGainPerSqm>9.69</averageInternGainPerSqm>
<convectiveFraction>0.40</convectiveFraction>
<radiantFraction>0.50</radiantFraction>
<latentFraction>0.10</latentFraction>
</internGains>
</occupancy>
<appliance units="kWh/day">19.5</appliance>
<endUses>
<space_heating>
<heatingSetPointTemperature>19.0</heatingSetPointTemperature>
<heatingSetBackTemperature>18.0</heatingSetBackTemperature>
</space_heating>
<space_cooling>
<coolingSetPointTemperature>21.0</coolingSetPointTemperature>
</space_cooling>
<ventilation>
<mechanicalAirChangeRate>0</mechanicalAirChangeRate>
</ventilation>
</endUses>
</zoneUsageType>
</buildingUsageLibrary>

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<nrcan base_url="https://raw.githubusercontent.com/NREL/openstudio-standards/master/lib/openstudio-standards/standards/necb/"> <nrcan base_url="https://raw.githubusercontent.com/NREL/openstudio-standards/master/lib/openstudio-standards/standards/necb/">
<standards> <space_types_location>NECB2020/data/space_types.json</space_types_location>
<usage> <schedules_location>NECB2015/data/schedules.json</schedules_location>
<space_types_location>NECB2020/data/space_types.json</space_types_location>
<schedules_location>NECB2015/data/schedules.json</schedules_location>
</usage>
</standards>
</nrcan> </nrcan>

View File

@ -75,7 +75,7 @@ class EnergyAde:
'energy:type': 'grossVolume', 'energy:type': 'grossVolume',
'energy:value': { 'energy:value': {
'@uom': 'm3', '@uom': 'm3',
'energy:value': building.volume '#text': f'{building.volume}'
} }
} }
} }
@ -169,7 +169,7 @@ class EnergyAde:
def _building_geometry(self, building, building_dic, city): def _building_geometry(self, building, building_dic, city):
building_dic['bldg:Building']['bldg:function'] = building.function building_dic['bldg:Building']['bldg:function'] = building.function
building_dic['bldg:Building']['bldg:usage'] = ', '.join([u.usage for u in building.usage_zones]) building_dic['bldg:Building']['bldg:usage'] = building.usages_percentage
building_dic['bldg:Building']['bldg:yearOfConstruction'] = building.year_of_construction building_dic['bldg:Building']['bldg:yearOfConstruction'] = building.year_of_construction
building_dic['bldg:Building']['bldg:roofType'] = building.roof_type building_dic['bldg:Building']['bldg:roofType'] = building.roof_type
building_dic['bldg:Building']['bldg:measuredHeight'] = { building_dic['bldg:Building']['bldg:measuredHeight'] = {
@ -178,16 +178,86 @@ class EnergyAde:
} }
building_dic['bldg:Building']['bldg:storeysAboveGround'] = building.storeys_above_ground building_dic['bldg:Building']['bldg:storeysAboveGround'] = building.storeys_above_ground
if building.lod == 1: if city.level_of_detail.geometry == 1:
building_dic = self._lod1(building, building_dic, city) building_dic = self._lod1(building, building_dic, city)
elif building.lod == 2: elif city.level_of_detail.geometry == 2:
building_dic = self._lod2(building, building_dic, city) building_dic = self._lod2(building, building_dic, city)
else: else:
raise NotImplementedError('Only lod 1 and 2 can be exported') raise NotImplementedError('Only lod 1 and 2 can be exported')
return building_dic return building_dic
def _lod1(self, building, building_dic, city): def _lod1(self, building, building_dic, city):
raise NotImplementedError('Only lod 1 and 2 can be exported') self._surface_members = []
boundaries = [{
'gml:Envelope': {
'@srsName': city.srs_name,
'@srsDimension': 3,
'gml:lowerCorner': ' '.join([str(e) for e in city.lower_corner]),
'gml:upperCorner': ' '.join([str(e) for e in city.upper_corner])
}}]
for surface in building.surfaces:
surface_member = {'@xlink:href': f'#PolyId{surface.name}'}
self._surface_members.append(surface_member)
if surface.type == 'Wall':
surface_type = 'bldg:WallSurface'
elif surface.type == 'Ground':
surface_type = 'bldg:GroundSurface'
else:
surface_type = 'bldg:RoofSurface'
surface_dic = {
surface_type: {
'@gml:id': f'GML_{uuid.uuid4()}',
'gml:name': f'{surface.name} ({surface.type})',
'gml:boundedBy': {
'gml:Envelope': {
'@srsName': city.srs_name,
'gml:lowerCorner': f'{surface.lower_corner[0]} {surface.lower_corner[1]}'
f' {surface.lower_corner[2]}',
'gml:upperCorner': f'{surface.upper_corner[0]} {surface.upper_corner[1]}'
f' {surface.upper_corner[2]}'
}
},
'bldg:lod1MultiSurface': {
'gml:MultiSurface': {
'@srsName': city.srs_name,
'@gml:id': f'GML_{uuid.uuid4()}',
'surfaceMember': {
'gml:Polygon': {
'@srsName': city.srs_name,
'@gml:id': f'PolyId{surface.name}',
'gml:exterior': {
'gml:LinearRing': {
'@gml:id': f'PolyId{surface.name}_0',
'gml:posList': {
'@srsDimension': '3',
'@count': len(surface.solid_polygon.coordinates) + 1,
'#text': f'{" ".join(map(str, surface.solid_polygon.points_list))} '
f'{" ".join(map(str, surface.solid_polygon.coordinates[0]))}'
}
}
}
}
}
}
}
}
}
boundaries.append(surface_dic)
building_dic['bldg:Building']['bldg:lod1Solid'] = {
'gml:Solid': {
'@gml:id': f'GML_{uuid.uuid4()}',
'gml:exterior': {
'gml:CompositeSurface': {
'@srsName': city.srs_name,
'@gml:id': f'GML_{uuid.uuid4()}',
'gml:surfaceMember': self._surface_members
}
}
}
}
building_dic['bldg:Building']['gml:boundedBy'] = boundaries
return building_dic
def _lod2(self, building, building_dic, city): def _lod2(self, building, building_dic, city):
self._surface_members = [] self._surface_members = []
@ -264,56 +334,57 @@ class EnergyAde:
def _thermal_zones(self, building, city): def _thermal_zones(self, building, city):
thermal_zones = [] thermal_zones = []
for index, thermal_zone in enumerate(building.thermal_zones): for internal_zone in building.internal_zones:
usage_zones = [] for index, thermal_zone in enumerate(internal_zone.thermal_zones):
for usage_zone in thermal_zone.usage_zones: usages = []
usage_zones.append({'@xlink:href': f'#GML_{usage_zone.id}'}) for usage in internal_zone.usages:
thermal_zone_dic = { usages.append({'@xlink:href': f'#GML_{usage.id}'})
'energy:ThermalZone': { thermal_zone_dic = {
'@gml:id': f'GML_{thermal_zone.id}', 'energy:ThermalZone': {
'gml:name': f'Thermal zone {index} in {building.name} building', '@gml:id': f'GML_{thermal_zone.id}',
'energy:contains': [], 'gml:name': f'Thermal zone {index} in {building.name} building',
'energy:floorArea': { 'energy:contains': [],
'energy:FloorArea': { 'energy:floorArea': {
'energy:type': 'grossFloorArea', 'energy:FloorArea': {
'energy:value': { 'energy:type': 'grossFloorArea',
'@uom': 'm2', 'energy:value': {
'#text': f'{thermal_zone.footprint_area}' '@uom': 'm2',
} '#text': f'{thermal_zone.footprint_area}'
}
},
'energy:volume': {
'energy:VolumeType': {
'energy:type': 'grossVolume',
'energy:value': {
'@uom': 'm3',
# todo: for now we have just one thermal zone, therefore is the building volume, this need to be changed
'#text': f'{building.volume}'
}
}
},
'energy:isCooled': f'{thermal_zone.is_cooled}',
'energy:isHeated': f'{thermal_zone.is_heated}',
'energy:volumeGeometry': {
'gml:Solid': {
'@gml:id': f'GML_{uuid.uuid4()}',
'gml:exterior': {
'gml:CompositeSurface': {
'@srsName': f'{city.srs_name}',
'@gml:id': f'GML_{uuid.uuid4()}',
'gml:surfaceMember': self._surface_members
} }
} }
} },
}, 'energy:volume': {
'energy:boundedBy': self._thermal_boundaries(city, thermal_zone) 'energy:VolumeType': {
'energy:type': 'grossVolume',
'energy:value': {
'@uom': 'm3',
'#text': f'{thermal_zone.volume}'
}
}
},
'energy:isCooled': f'{building.is_conditioned}'.lower(),
'energy:isHeated': f'{building.is_conditioned}'.lower(),
'energy:volumeGeometry': {
'gml:Solid': {
'@gml:id': f'GML_{uuid.uuid4()}',
'gml:exterior': {
'gml:CompositeSurface': {
'@srsName': f'{city.srs_name}',
'@gml:id': f'GML_{uuid.uuid4()}',
'gml:surfaceMember': self._surface_members
}
}
}
},
'energy:boundedBy': self._thermal_boundaries(city, thermal_zone)
}
} }
} thermal_zone_dic['energy:ThermalZone']['energy:contains'] = usages
thermal_zone_dic['energy:ThermalZone']['energy:contains'] = usage_zones thermal_zones.append(thermal_zone_dic)
thermal_zones.append(thermal_zone_dic)
return thermal_zones return thermal_zones
def _thermal_boundaries(self, city, thermal_zone): @staticmethod
def _thermal_boundaries(city, thermal_zone):
thermal_boundaries = [] thermal_boundaries = []
for thermal_boundary in thermal_zone.thermal_boundaries: for thermal_boundary in thermal_zone.thermal_boundaries:
thermal_boundary_dic = { thermal_boundary_dic = {
@ -322,11 +393,11 @@ class EnergyAde:
'energy:thermalBoundaryType': thermal_boundary.type, 'energy:thermalBoundaryType': thermal_boundary.type,
'energy:azumuth': { 'energy:azumuth': {
'@uom': 'rad', '@uom': 'rad',
'#text': f'{thermal_boundary.azimuth}' '#text': f'{thermal_boundary.parent_surface.azimuth}'
}, },
'energy:inclination': { 'energy:inclination': {
'@uom': 'rad', '@uom': 'rad',
'#text': f'{thermal_boundary.inclination}' '#text': f'{thermal_boundary.parent_surface.inclination}'
}, },
'energy:area': { 'energy:area': {
'@uom': 'm2', '@uom': 'm2',
@ -345,9 +416,9 @@ class EnergyAde:
'@gml:id': f'GML_{uuid.uuid4()}', '@gml:id': f'GML_{uuid.uuid4()}',
'gml:posList': { 'gml:posList': {
'@srsDimension': '3', '@srsDimension': '3',
'@count': len(thermal_boundary.surface.solid_polygon.coordinates) + 1, '@count': len(thermal_boundary.parent_surface.solid_polygon.coordinates) + 1,
'#text': f'{" ".join(map(str, thermal_boundary.surface.solid_polygon.points_list))} ' '#text': f'{" ".join(map(str, thermal_boundary.parent_surface.solid_polygon.points_list))} '
f'{" ".join(map(str, thermal_boundary.surface.solid_polygon.coordinates[0]))}' f'{" ".join(map(str, thermal_boundary.parent_surface.solid_polygon.coordinates[0]))}'
} }
} }
} }
@ -364,7 +435,7 @@ class EnergyAde:
'@xlink:href': f'#GML_{construction[0]}' '@xlink:href': f'#GML_{construction[0]}'
} }
if thermal_boundary.thermal_openings is not None: if thermal_boundary.thermal_openings is not None:
for opening in thermal_boundary.thermal_openings: for _ in thermal_boundary.thermal_openings:
opening_construction.append(uuid.uuid4()) opening_construction.append(uuid.uuid4())
thermal_boundary_dic['energy:contains'] = { thermal_boundary_dic['energy:contains'] = {
'energy:ThermalOpening': { 'energy:ThermalOpening': {

View File

@ -206,9 +206,9 @@ class Idf:
_schedule.values = _infiltration_values _schedule.values = _infiltration_values
_infiltration_schedules.append(_schedule) _infiltration_schedules.append(_schedule)
for schedule in self._idf.idfobjects[self._HOURLY_SCHEDULE]: for schedule in self._idf.idfobjects[self._HOURLY_SCHEDULE]:
if schedule.Name == f'Infiltration schedules {thermal_zone.usage}': if schedule.Name == f'Infiltration schedules {thermal_zone.usage_name}':
return return
return self._add_standard_compact_hourly_schedule(thermal_zone.usage, 'Infiltration', _infiltration_schedules) return self._add_standard_compact_hourly_schedule(thermal_zone.usage_name, 'Infiltration', _infiltration_schedules)
def _add_people_activity_level_schedules(self, thermal_zone): def _add_people_activity_level_schedules(self, thermal_zone):
_occ = thermal_zone.occupancy _occ = thermal_zone.occupancy
@ -218,9 +218,9 @@ class Idf:
_total_heat = (_occ.sensible_convective_internal_gain + _occ.sensible_radiative_internal_gain _total_heat = (_occ.sensible_convective_internal_gain + _occ.sensible_radiative_internal_gain
+ _occ.latent_internal_gain) / _occ.occupancy_density + _occ.latent_internal_gain) / _occ.occupancy_density
for schedule in self._idf.idfobjects[self._COMPACT_SCHEDULE]: for schedule in self._idf.idfobjects[self._COMPACT_SCHEDULE]:
if schedule.Name == f'Activity Level schedules {thermal_zone.usage}': if schedule.Name == f'Activity Level schedules {thermal_zone.usage_name}':
return return
_kwargs = {'Name': f'Activity Level schedules {thermal_zone.usage}', _kwargs = {'Name': f'Activity Level schedules {thermal_zone.usage_name}',
'Schedule_Type_Limits_Name': self.idf_type_limits[cte.ANY_NUMBER], 'Schedule_Type_Limits_Name': self.idf_type_limits[cte.ANY_NUMBER],
'Field_1': 'Through: 12/31', 'Field_1': 'Through: 12/31',
'Field_2': 'For AllDays', 'Field_2': 'For AllDays',
@ -299,15 +299,15 @@ class Idf:
self._add_heating_system(thermal_zone, name) self._add_heating_system(thermal_zone, name)
def _add_thermostat(self, thermal_zone): def _add_thermostat(self, thermal_zone):
thermostat_name = f'Thermostat {thermal_zone.usage}' thermostat_name = f'Thermostat {thermal_zone.usage_name}'
for thermostat in self._idf.idfobjects[self._THERMOSTAT]: for thermostat in self._idf.idfobjects[self._THERMOSTAT]:
if thermostat.Name == thermostat_name: if thermostat.Name == thermostat_name:
return thermostat return thermostat
# todo: change schedules to schedule name and create schedules using the add_schedule function # todo: change schedules to schedule name and create schedules using the add_schedule function
return self._idf.newidfobject(self._THERMOSTAT, return self._idf.newidfobject(self._THERMOSTAT,
Name=thermostat_name, Name=thermostat_name,
Heating_Setpoint_Schedule_Name=f'Heating thermostat schedules {thermal_zone.usage}', Heating_Setpoint_Schedule_Name=f'Heating thermostat schedules {thermal_zone.usage_name}',
Cooling_Setpoint_Schedule_Name=f'Cooling thermostat schedules {thermal_zone.usage}') Cooling_Setpoint_Schedule_Name=f'Cooling thermostat schedules {thermal_zone.usage_name}')
def _add_heating_system(self, thermal_zone, zone_name): def _add_heating_system(self, thermal_zone, zone_name):
for air_system in self._idf.idfobjects[self._IDEAL_LOAD_AIR_SYSTEM]: for air_system in self._idf.idfobjects[self._IDEAL_LOAD_AIR_SYSTEM]:
@ -316,9 +316,9 @@ class Idf:
thermostat = self._add_thermostat(thermal_zone) thermostat = self._add_thermostat(thermal_zone)
self._idf.newidfobject(self._IDEAL_LOAD_AIR_SYSTEM, self._idf.newidfobject(self._IDEAL_LOAD_AIR_SYSTEM,
Zone_Name=zone_name, Zone_Name=zone_name,
System_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage}', System_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage_name}',
Heating_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage}', Heating_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage_name}',
Cooling_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage}', Cooling_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage_name}',
Template_Thermostat_Name=thermostat.Name) Template_Thermostat_Name=thermostat.Name)
def _add_occupancy(self, thermal_zone, zone_name): def _add_occupancy(self, thermal_zone, zone_name):
@ -329,11 +329,11 @@ class Idf:
self._idf.newidfobject(self._PEOPLE, self._idf.newidfobject(self._PEOPLE,
Name=f'{zone_name}_occupancy', Name=f'{zone_name}_occupancy',
Zone_or_ZoneList_Name=zone_name, Zone_or_ZoneList_Name=zone_name,
Number_of_People_Schedule_Name=f'Occupancy schedules {thermal_zone.usage}', Number_of_People_Schedule_Name=f'Occupancy schedules {thermal_zone.usage_name}',
Number_of_People_Calculation_Method="People", Number_of_People_Calculation_Method="People",
Number_of_People=number_of_people, Number_of_People=number_of_people,
Fraction_Radiant=fraction_radiant, Fraction_Radiant=fraction_radiant,
Activity_Level_Schedule_Name=f'Activity Level schedules {thermal_zone.usage}' Activity_Level_Schedule_Name=f'Activity Level schedules {thermal_zone.usage_name}'
) )
def _add_infiltration(self, thermal_zone, zone_name): def _add_infiltration(self, thermal_zone, zone_name):
@ -343,7 +343,7 @@ class Idf:
self._idf.newidfobject(self._INFILTRATION, self._idf.newidfobject(self._INFILTRATION,
Name=f'{zone_name}_infiltration', Name=f'{zone_name}_infiltration',
Zone_or_ZoneList_Name=zone_name, Zone_or_ZoneList_Name=zone_name,
Schedule_Name=f'Infiltration schedules {thermal_zone.usage}', Schedule_Name=f'Infiltration schedules {thermal_zone.usage_name}',
Design_Flow_Rate_Calculation_Method='AirChanges/Hour', Design_Flow_Rate_Calculation_Method='AirChanges/Hour',
Air_Changes_per_Hour=thermal_zone.mechanical_air_change Air_Changes_per_Hour=thermal_zone.mechanical_air_change
) )
@ -386,7 +386,7 @@ class Idf:
self._add_vegetation_material(thermal_boundary.parent_surface.vegetation) self._add_vegetation_material(thermal_boundary.parent_surface.vegetation)
for thermal_opening in thermal_boundary.thermal_openings: for thermal_opening in thermal_boundary.thermal_openings:
self._add_window_construction_and_material(thermal_opening) self._add_window_construction_and_material(thermal_opening)
usage = thermal_zone.usage usage = thermal_zone.usage_name
if building.name in self._target_buildings or building.name in self._adjacent_buildings: if building.name in self._target_buildings or building.name in self._adjacent_buildings:
self._add_infiltration_schedules(thermal_zone) self._add_infiltration_schedules(thermal_zone)
self._add_schedules(usage, 'Occupancy', thermal_zone.occupancy.occupancy_schedules) self._add_schedules(usage, 'Occupancy', thermal_zone.occupancy.occupancy_schedules)
@ -461,8 +461,8 @@ class Idf:
if surface.Type == self.idf_surfaces[boundary.surface.type]: if surface.Type == self.idf_surfaces[boundary.surface.type]:
surface.Construction_Name = boundary.construction_name surface.Construction_Name = boundary.construction_name
break break
for usage_zone in thermal_zone.usage_zones: for usage in thermal_zone.usages:
surface.Zone_Name = usage_zone.id surface.Zone_Name = usage.id
break break
break break
self._idf.intersect_match() self._idf.intersect_match()

View File

@ -77,25 +77,25 @@ class InselMonthlyEnergyBalance(Insel):
parameters.append('1 % BP(9) Usage type (0=standard, 1=IWU)') parameters.append('1 % BP(9) Usage type (0=standard, 1=IWU)')
# ZONES AND SURFACES # ZONES AND SURFACES
parameters.append(f'{len(internal_zone.usage_zones)} % BP(10) Number of zones') parameters.append(f'{len(internal_zone.usages)} % BP(10) Number of zones')
for i, usage_zone in enumerate(internal_zone.usage_zones): for i, usage in enumerate(internal_zone.usages):
percentage_usage = usage_zone.percentage percentage_usage = usage.percentage
parameters.append(f'{float(internal_zone.area) * percentage_usage} % BP(11) #1 Area of zone {i + 1} (m2)') parameters.append(f'{float(internal_zone.area) * percentage_usage} % BP(11) #1 Area of zone {i + 1} (m2)')
total_internal_gain = 0 total_internal_gain = 0
for ig in usage_zone.internal_gains: for ig in usage.internal_gains:
total_internal_gain += float(ig.average_internal_gain) * \ total_internal_gain += float(ig.average_internal_gain) * \
(float(ig.convective_fraction) + float(ig.radiative_fraction)) (float(ig.convective_fraction) + float(ig.radiative_fraction))
parameters.append(f'{total_internal_gain} % BP(12) #2 Internal gains of zone {i + 1}') parameters.append(f'{total_internal_gain} % BP(12) #2 Internal gains of zone {i + 1}')
parameters.append(f'{usage_zone.thermal_control.mean_heating_set_point} % BP(13) #3 Heating setpoint temperature ' parameters.append(f'{usage.thermal_control.mean_heating_set_point} % BP(13) #3 Heating setpoint temperature '
f'zone {i + 1} (degree Celsius)') f'zone {i + 1} (degree Celsius)')
parameters.append(f'{usage_zone.thermal_control.heating_set_back} % BP(14) #4 Heating setback temperature ' parameters.append(f'{usage.thermal_control.heating_set_back} % BP(14) #4 Heating setback temperature '
f'zone {i + 1} (degree Celsius)') f'zone {i + 1} (degree Celsius)')
parameters.append(f'{usage_zone.thermal_control.mean_cooling_set_point} % BP(15) #5 Cooling setpoint temperature ' parameters.append(f'{usage.thermal_control.mean_cooling_set_point} % BP(15) #5 Cooling setpoint temperature '
f'zone {i + 1} (degree Celsius)') f'zone {i + 1} (degree Celsius)')
parameters.append(f'{usage_zone.hours_day} % BP(16) #6 Usage hours per day zone {i + 1}') parameters.append(f'{usage.hours_day} % BP(16) #6 Usage hours per day zone {i + 1}')
parameters.append(f'{usage_zone.days_year} % BP(17) #7 Usage days per year zone {i + 1}') parameters.append(f'{usage.days_year} % BP(17) #7 Usage days per year zone {i + 1}')
parameters.append(f'{usage_zone.mechanical_air_change} % BP(18) #8 Minimum air change rate zone {i + 1} (ACH)') parameters.append(f'{usage.mechanical_air_change} % BP(18) #8 Minimum air change rate zone {i + 1} (ACH)')
parameters.append(f'{len(thermal_zone.thermal_boundaries)} % Number of surfaces = BP(11+8z) \n' parameters.append(f'{len(thermal_zone.thermal_boundaries)} % Number of surfaces = BP(11+8z) \n'
f'% 1. Surface type (1=wall, 2=ground 3=roof, 4=flat roof)\n' f'% 1. Surface type (1=wall, 2=ground 3=roof, 4=flat roof)\n'
@ -167,6 +167,8 @@ class InselMonthlyEnergyBalance(Insel):
f'inclination {np.rad2deg(surface.inclination)} (degrees)'] f'inclination {np.rad2deg(surface.inclination)} (degrees)']
if surface.type != 'Ground': if surface.type != 'Ground':
if cte.MONTH not in surface.global_irradiance:
raise ValueError(f'surface: {surface.name} from building {building.name} has no global irradiance!')
global_irradiance = surface.global_irradiance[cte.MONTH] global_irradiance = surface.global_irradiance[cte.MONTH]
for j in range(0, len(global_irradiance)): for j in range(0, len(global_irradiance)):
parameters.append(f'{j + 1} {global_irradiance.at[j, radiation_calculation_method]}') parameters.append(f'{j + 1} {global_irradiance.at[j, radiation_calculation_method]}')
@ -176,15 +178,17 @@ class InselMonthlyEnergyBalance(Insel):
file = Insel._add_block(file, i_block, 'polyg', inputs=inputs, parameters=parameters) file = Insel._add_block(file, i_block, 'polyg', inputs=inputs, parameters=parameters)
i_block = 300 i_block = 300 + len(surfaces)
inputs = ['4.1', '4.2'] inputs = ['4.1', '4.2']
file = Insel._add_block(file, i_block, 'cum', inputs=inputs) file = Insel._add_block(file, i_block, 'cum', inputs=inputs)
i_block = 303 in_1 = f'{i_block}.1'
inputs = ['300.1', '300.2'] in_2 = f'{i_block}.2'
i_block = 303 + len(surfaces)
inputs = [in_1, in_2]
file = Insel._add_block(file, i_block, 'atend', inputs=inputs) file = Insel._add_block(file, i_block, 'atend', inputs=inputs)
i_block = 310 i_block = 310 + len(surfaces)
inputs = ['4.1', '4.2'] inputs = ['4.1', '4.2']
parameters = ['1 % Mode', parameters = ['1 % Mode',
'0 % Suppress FNQ inputs', '0 % Suppress FNQ inputs',

View File

@ -4,8 +4,10 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group Copyright © 2022 Concordia CERC group
Project CoderPeter Yefi peteryefi@gmail.com Project CoderPeter Yefi peteryefi@gmail.com
""" """
from hub.persistence import CityRepo from hub.persistence import City
from hub.persistence import HeatPumpSimulationRepo from hub.persistence import Application
from hub.persistence import User
from hub.persistence import CityObject
class DBFactory: class DBFactory:
@ -14,40 +16,38 @@ class DBFactory:
""" """
def __init__(self, db_name, app_env, dotenv_path): def __init__(self, db_name, app_env, dotenv_path):
self._city_repo = CityRepo(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path) self._city = City(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path)
self._hp_simulation_repo = HeatPumpSimulationRepo(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path) self._application = Application(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path)
self._user = User(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path)
self._city_object = CityObject(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path)
def get_city(self, city_id): def get_city(self, city_id):
""" """
Retrieve a single city from postgres Retrieve a single city from postgres
:param city_id: the id of the city to get :param city_id: the id of the city to get
""" """
return self._city_repo.get_by_id(city_id) return self._city.get_by_id(city_id)
def get_city_by_name(self, city_name): def get_city_by_name(self, city_name):
""" """
Retrieve a single city from postgres Retrieve a single city from postgres
:param city_name: the name of the city to get :param city_name: the name of the city to get
""" """
return self._city_repo.get_by_name(city_name) return self._city.get_by_name(city_name)
def get_city_by_user(self, user_id): def get_city_by_user(self, user_id):
""" """
Retrieve cities created by user Retrieve cities created by user
:param user_id: the id of the user :param user_id: the id of the user
""" """
return self._city_repo.get_by_user(user_id) return self._city.get_by_user(user_id)
def get_hp_simulation(self, hp_sim_id: int): def application_info(self, application_uuid):
""" return self._application.get_by_uuid(application_uuid)
Retrieve a single heat pump simulation from postgres
:param hp_sim_id: the id of the heat pump to get def user_info(self, name, password, application_id):
""" return self._user.get_by_name_application_and_password(name, password, application_id)
return self._hp_simulation_repo.get_by_id(hp_sim_id)
def building_info(self, name, city_id):
return self._city_object.get_by_name_and_city(name, city_id)
def get_hp_simulation_by_city(self, city_id: int):
"""
Retrieve a single city from postgres
:param city_id: the id of the city
"""
return self._hp_simulation_repo.get_by_city(city_id)

View File

@ -9,6 +9,8 @@ from pathlib import Path
from hub.exports.building_energy.energy_ade import EnergyAde from hub.exports.building_energy.energy_ade import EnergyAde
from hub.exports.building_energy.idf import Idf from hub.exports.building_energy.idf import Idf
from hub.exports.building_energy.insel.insel_monthly_energy_balance import InselMonthlyEnergyBalance from hub.exports.building_energy.insel.insel_monthly_energy_balance import InselMonthlyEnergyBalance
from hub.helpers.utils import validate_import_export_type
from hub.hub_logger import logger
class EnergyBuildingsExportsFactory: class EnergyBuildingsExportsFactory:
@ -18,6 +20,11 @@ class EnergyBuildingsExportsFactory:
def __init__(self, export_type, city, path, target_buildings=None, adjacent_buildings=None): def __init__(self, export_type, city, path, target_buildings=None, adjacent_buildings=None):
self._city = city self._city = city
self._export_type = '_' + export_type.lower() self._export_type = '_' + export_type.lower()
class_funcs = validate_import_export_type(EnergyBuildingsExportsFactory)
if self._export_type not in class_funcs:
err_msg = f"Wrong import type [{self._export_type}]. Valid functions include {class_funcs}"
logger.error(err_msg)
raise Exception(err_msg)
if isinstance(path, str): if isinstance(path, str):
path = Path(path) path = Path(path)
self._path = path self._path = path

View File

@ -64,8 +64,8 @@ class HeatPumpExport:
# User output # User output
return self._get_user_out_put() return self._get_user_out_put()
except IOError as err: except IOError as err:
print("I/O exception: {}".format(err)) print("I/O exception: {}".format(str(err)))
logger.error(f'An I/O error occurred while running insel: {err}') logger.error(f'An I/O error occurred while running insel: {str(err)}')
finally: finally:
insel_file_handler.close() insel_file_handler.close()
insel_template_handler.close() insel_template_handler.close()
@ -252,5 +252,3 @@ class HeatPumpExport:
s = pd.Series(["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec", "Total"]) s = pd.Series(["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec", "Total"])
df = df.set_index([s]) df = df.set_index([s])
df.to_csv(self._output_path) df.to_csv(self._output_path)

View File

@ -9,20 +9,33 @@ from pathlib import Path
from hub.exports.formats.obj import Obj from hub.exports.formats.obj import Obj
from hub.exports.formats.simplified_radiosity_algorithm import SimplifiedRadiosityAlgorithm from hub.exports.formats.simplified_radiosity_algorithm import SimplifiedRadiosityAlgorithm
from hub.exports.formats.stl import Stl from hub.exports.formats.stl import Stl
from hub.hub_logger import logger
from hub.helpers.utils import validate_import_export_type
class ExportsFactory: class ExportsFactory:
""" """
Exports factory class Exports factory class
""" """
def __init__(self, export_type, city, path, target_buildings=None, adjacent_buildings=None): def __init__(self, export_type, city, path,
target_buildings=None,
adjacent_buildings=None,
weather_file=None,
weather_format=None):
self._city = city self._city = city
self._export_type = '_' + export_type.lower() self._export_type = '_' + export_type.lower()
class_funcs = validate_import_export_type(ExportsFactory)
if self._export_type not in class_funcs:
err_msg = f"Wrong export type [{self._export_type}]. Valid functions include {class_funcs}"
logger.error(err_msg)
raise Exception(err_msg)
if isinstance(path, str): if isinstance(path, str):
path = Path(path) path = Path(path)
self._path = path self._path = path
self._target_buildings = target_buildings self._target_buildings = target_buildings
self._adjacent_buildings = adjacent_buildings self._adjacent_buildings = adjacent_buildings
self._weather_file = weather_file
self._weather_format = weather_format
@property @property
def _citygml(self): def _citygml(self):
@ -66,7 +79,10 @@ class ExportsFactory:
Export the city to Simplified Radiosity Algorithm xml format Export the city to Simplified Radiosity Algorithm xml format
:return: None :return: None
""" """
return SimplifiedRadiosityAlgorithm(self._city, (self._path / f'{self._city.name}_sra.xml'), return SimplifiedRadiosityAlgorithm(self._city,
(self._path / f'{self._city.name}_sra.xml'),
self._weather_file,
self._weather_format,
target_buildings=self._target_buildings) target_buildings=self._target_buildings)
def export(self): def export(self):

View File

@ -27,4 +27,3 @@ class Insel(ABC):
def _export(self): def _export(self):
raise NotImplementedError raise NotImplementedError

View File

@ -26,7 +26,8 @@ class Obj(Triangular):
file_name_out = self._city.name + '_ground.' + self._triangular_format file_name_out = self._city.name + '_ground.' + self._triangular_format
file_path_in = (Path(self._path).resolve() / file_name_in).resolve() file_path_in = (Path(self._path).resolve() / file_name_in).resolve()
file_path_out = (Path(self._path).resolve() / file_name_out).resolve() file_path_out = (Path(self._path).resolve() / file_name_out).resolve()
scene = GeometryFactory('obj', path=file_path_in).scene obj = GeometryFactory('obj', path=file_path_in)
scene = obj.scene
scene.rezero() scene.rezero()
obj_file = trimesh.exchange.obj.export_obj(scene) obj_file = trimesh.exchange.obj.export_obj(scene)
with open(file_path_out, 'w') as file: with open(file_path_out, 'w') as file:

View File

@ -6,12 +6,25 @@ Project Coder Guillermo.GutierrezMorote@concordia.ca
""" """
import xmltodict import xmltodict
from hub.imports.weather_factory import WeatherFactory
import hub.helpers.constants as cte
class SimplifiedRadiosityAlgorithm: class SimplifiedRadiosityAlgorithm:
""" """
Export to SRA format Export to SRA format
""" """
def __init__(self, city, file_name, target_buildings=None, begin_month=1, begin_day=1, end_month=12, end_day=31):
def __init__(self,
city,
file_name,
weather_file,
weather_format,
target_buildings=None,
begin_month=1,
begin_day=1,
end_month=12,
end_day=31):
self._file_name = file_name self._file_name = file_name
self._begin_month = begin_month self._begin_month = begin_month
self._begin_day = begin_day self._begin_day = begin_day
@ -19,6 +32,8 @@ class SimplifiedRadiosityAlgorithm:
self._end_day = end_day self._end_day = end_day
self._city = city self._city = city
self._target_buildings = target_buildings self._target_buildings = target_buildings
self._weather_format = weather_format
self._weather_file = weather_file
self._export() self._export()
def _correct_point(self, point): def _correct_point(self, point):
@ -29,6 +44,34 @@ class SimplifiedRadiosityAlgorithm:
return [x, y, z] return [x, y, z]
def _export(self): def _export(self):
self._export_sra_xml()
self._export_sra_cli()
def _export_sra_cli(self):
file = self._city.climate_file
days_in_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
WeatherFactory(self._weather_format, self._city, file_name=self._weather_file).enrich()
content = self._city.name + '\n'
content += str(self._city.latitude) + ',' + str(self._city.longitude) + ',0.0,' + str(self._city.time_zone) + '\n'
content += '\ndm m h G_Dh G_Bn\n'
total_days = 0
for month in range(1, 13):
if month > 1:
total_days += days_in_month[month - 2]
for day in range(1, days_in_month[month - 1] + 1):
for hour in range(1, 25):
if month == 1:
i = 24 * (day - 1) + hour - 1
else:
i = (total_days + day - 1) * 24 + hour - 1
representative_building = self._city.buildings[0]
content += str(day) + ' ' + str(month) + ' ' + str(hour) + ' ' \
+ str(representative_building.global_horizontal[cte.HOUR].epw[i]) + ' ' \
+ str(representative_building.beam[cte.HOUR].epw[i]) + '\n'
with open(file, "w") as file:
file.write(content)
def _export_sra_xml(self):
buildings = [] buildings = []
for building_index, building in enumerate(self._city.buildings): for building_index, building in enumerate(self._city.buildings):
if self._target_buildings is None: if self._target_buildings is None:

View File

@ -1,23 +1,16 @@
"""
Constant module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Peter Yefi peteryefi@gmail.com
"""
import bcrypt import bcrypt
import re import re
class Auth(object): class Auth(object):
@staticmethod
def validate_password(password: str) -> bool:
"""
Validates a password
:param password: the password to validate
:return:
"""
pattern = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!#%*?&]{6,20}$"
pattern = re.compile(pattern)
if not re.search(pattern, password):
raise ValueError("Password must be between 6 to 20 characters and must have at least a number, an uppercase "
"letter, a lowercase letter, and a special character")
return True
@staticmethod @staticmethod
def hash_password(password: str) -> str: def hash_password(password: str) -> str:
""" """

View File

@ -66,45 +66,64 @@ DOOR = 'Door'
SKYLIGHT = 'Skylight' SKYLIGHT = 'Skylight'
# functions and usages # functions and usages
RESIDENTIAL = 'residential'
SINGLE_FAMILY_HOUSE = 'single family house' SINGLE_FAMILY_HOUSE = 'single family house'
MULTI_FAMILY_HOUSE = 'multifamily house' MULTI_FAMILY_HOUSE = 'multifamily house'
ROW_HOSE = 'row house' ROW_HOUSE = 'row house'
MID_RISE_APARTMENT = 'mid rise apartment' MID_RISE_APARTMENT = 'mid rise apartment'
HIGH_RISE_APARTMENT = 'high rise apartment' HIGH_RISE_APARTMENT = 'high rise apartment'
OFFICE_AND_ADMINISTRATION = 'office and administration'
SMALL_OFFICE = 'small office' SMALL_OFFICE = 'small office'
MEDIUM_OFFICE = 'medium office' MEDIUM_OFFICE = 'medium office'
LARGE_OFFICE = 'large office' LARGE_OFFICE = 'large office'
COURTHOUSE = 'courthouse'
FIRE_STATION = 'fire station'
PENITENTIARY = 'penitentiary'
POLICE_STATION = 'police station'
POST_OFFICE = 'post office'
LIBRARY = 'library'
EDUCATION = 'education'
PRIMARY_SCHOOL = 'primary school' PRIMARY_SCHOOL = 'primary school'
PRIMARY_SCHOOL_WITH_SHOWER = 'school with shower'
SECONDARY_SCHOOL = 'secondary school' SECONDARY_SCHOOL = 'secondary school'
UNIVERSITY = 'university'
LABORATORY_AND_RESEARCH_CENTER = 'laboratory and research centers'
STAND_ALONE_RETAIL = 'stand alone retail' STAND_ALONE_RETAIL = 'stand alone retail'
HOSPITAL = 'hospital' HOSPITAL = 'hospital'
OUT_PATIENT_HEALTH_CARE = 'out-patient health care' OUT_PATIENT_HEALTH_CARE = 'out-patient health care'
STRIP_MALL = 'strip mall'
SUPERMARKET = 'supermarket'
WAREHOUSE = 'warehouse'
QUICK_SERVICE_RESTAURANT = 'quick service restaurant'
FULL_SERVICE_RESTAURANT = 'full service restaurant'
SMALL_HOTEL = 'small hotel'
LARGE_HOTEL = 'large hotel'
RESIDENTIAL = 'residential'
EDUCATION = 'education'
SCHOOL_WITHOUT_SHOWER = 'school without shower'
SCHOOL_WITH_SHOWER = 'school with shower'
RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD = 'retail shop without refrigerated food'
RETAIL_SHOP_WITH_REFRIGERATED_FOOD = 'retail shop with refrigerated food'
HOTEL = 'hotel'
HOTEL_MEDIUM_CLASS = 'hotel medium class'
DORMITORY = 'dormitory'
INDUSTRY = 'industry'
RESTAURANT = 'restaurant'
HEALTH_CARE = 'health care' HEALTH_CARE = 'health care'
RETIREMENT_HOME_OR_ORPHANAGE = 'retirement home or orphanage' RETIREMENT_HOME_OR_ORPHANAGE = 'retirement home or orphanage'
OFFICE_AND_ADMINISTRATION = 'office and administration' COMMERCIAL = 'commercial'
STRIP_MALL = 'strip mall'
SUPERMARKET = 'supermarket'
RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD = 'retail shop without refrigerated food'
RETAIL_SHOP_WITH_REFRIGERATED_FOOD = 'retail shop with refrigerated food'
RESTAURANT = 'restaurant'
QUICK_SERVICE_RESTAURANT = 'quick service restaurant'
FULL_SERVICE_RESTAURANT = 'full service restaurant'
HOTEL = 'hotel'
HOTEL_MEDIUM_CLASS = 'hotel medium class'
SMALL_HOTEL = 'small hotel'
LARGE_HOTEL = 'large hotel'
DORMITORY = 'dormitory'
EVENT_LOCATION = 'event location' EVENT_LOCATION = 'event location'
CONVENTION_CENTER = 'convention center'
HALL = 'hall' HALL = 'hall'
SPORTS_LOCATION = 'sports location'
LABOR = 'labor'
GREEN_HOUSE = 'green house' GREEN_HOUSE = 'green house'
INDUSTRY = 'industry'
WORKSHOP = 'workshop'
WAREHOUSE = 'warehouse'
WAREHOUSE_REFRIGERATED = 'warehouse refrigerated'
SPORTS_LOCATION = 'sports location'
SPORTS_ARENA = 'sports arena'
GYMNASIUM = 'gymnasium'
MOTION_PICTURE_THEATRE = 'motion picture theatre'
MUSEUM = 'museum'
PERFORMING_ARTS_THEATRE = 'performing arts theatre'
TRANSPORTATION = 'transportation'
AUTOMOTIVE_FACILITY = 'automotive facility'
PARKING_GARAGE = 'parking garage'
RELIGIOUS = 'religious'
NON_HEATED = 'non-heated' NON_HEATED = 'non-heated'
LIGHTING = 'Lights' LIGHTING = 'Lights'
@ -133,3 +152,7 @@ FULL_HVAC = 'Heating and cooling and ventilation'
# Floats # Floats
MAX_FLOAT = float('inf') MAX_FLOAT = float('inf')
MIN_FLOAT = float('-inf') MIN_FLOAT = float('-inf')
# Tools
SRA = 'sra'
INSEL_MEB = 'insel meb'

View File

@ -0,0 +1,185 @@
"""
Dictionaries module for Alkis function to hub function
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
"""
import hub.helpers.constants as cte
class AlkisFunctionToHubFunction:
def __init__(self):
self._dictionary = {"1000": cte.RESIDENTIAL,
"1010": "tenement",
"1020": "hostel",
"1030": "residential- and administration building",
"1040": "residential- and office building",
"1050": "residential- and business building",
"1060": "residential- and plant building",
"1070": "agrarian- and forestry building",
"1080": "residential- and commercial building",
"1090": "forester's lodge",
"1100": "holiday house",
"1110": "summer house",
"1120": "office building",
"1130": "credit institution",
"1140": "insurance",
"1150": "business building",
"1160": "department store",
"1170": "shopping centre",
"1180": "kiosk",
"1190": "pharmacy",
"1200": "pavilion",
"1210": cte.HOTEL,
"1220": "youth hostel",
"1230": "campsite building",
"1240": "restaurant",
"1250": "cantine",
"1260": "recreational site",
"1270": "function room",
"1280": "cinema",
"1290": "bowling alley",
"1300": "casino",
"1310": "industrial building",
"1320": "factory",
"1330": cte.WORKSHOP,
"1340": "petrol / gas station",
"1350": "washing plant",
"1360": "cold store",
"1370": "depot",
"1380": "building for research purposes",
"1390": "quarry",
"1400": "salt works",
"1410": "miscellaneous industrial building",
"1420": "mill",
"1430": "windmill",
"1440": "water mill",
"1450": "bucket elevator",
"1460": "weather station",
"1470": "traffic assets office",
"1480": "street maintenance",
"1490": "waiting hall",
"1500": "signal control box",
"1510": "engine shed",
"1520": "signal box or stop signal",
"1530": "plant building for air traffic",
"1540": "hangar",
"1550": "plant building for shipping",
"1560": "shipyard",
"1570": "dock",
"1580": "plant building for canal lock",
"1590": "boathouse",
"1600": "plant building for cablecar",
"1610": "multi-storey car park",
"1620": "parking level",
"1630": "garage",
"1640": "vehicle hall",
"1650": "underground garage",
"1660": "building for supply",
"1670": "waterworks",
"1680": "pump station",
"1690": "water basin",
"1700": "electric power station",
"1710": "transformer station",
"1720": "converter",
"1730": "reactor",
"1740": "turbine house",
"1750": "boiler house",
"1760": "building for telecommunications",
"1770": "gas works",
"1780": "heat plant",
"1790": "pumping station",
"1800": "building for disposal",
"1810": "building for effluent disposal",
"1820": "building for filter plant",
"1830": "toilet",
"1840": "rubbish bunker",
"1850": "building for rubbish incineration",
"1860": "building for rubbish disposal",
"1870": "building for agrarian and forestry",
"1880": "barn",
"1890": "stall",
"1900": "equestrian hall",
"1910": "alpine cabin",
"1920": "hunting lodge",
"1930": "arboretum",
"1940": "glass house",
"1950": "moveable glass house",
"1960": "public building",
"1970": "administration building",
"1980": "parliament",
"1990": "guildhall",
"2000": "post office",
"2010": "customs office",
"2020": "court",
"2030": "embassy or consulate",
"2040": "district administration",
"2050": "district government",
"2060": "tax office",
"2070": "building for education and research",
"2080": "comprehensive school",
"2090": "vocational school",
"2100": "college or university",
"2110": "research establishment",
"2120": "building for cultural purposes",
"2130": "castle",
"2140": "theatre or opera",
"2150": "concert building",
"2160": cte.MUSEUM,
"2170": "broadcasting building",
"2180": "activity building",
"2190": cte.LIBRARY,
"2200": "fort",
"2210": "religious building",
"2220": "church",
"2230": "synagogue",
"2240": "chapel",
"2250": "community center",
"2260": "place of worship",
"2270": "mosque",
"2280": "temple",
"2290": "convent",
"2300": "building for health care",
"2310": cte.HOSPITAL,
"2320": "healing centre or care home",
"2330": "health centre or outpatients clinic",
"2340": "building for social purposes",
"2350": "youth centre",
"2360": "seniors centre",
"2370": "homeless shelter",
"2380": "kindergarten or nursery",
"2390": "asylum seekers home",
"2400": cte.POLICE_STATION,
"2410": cte.FIRE_STATION,
"2420": "barracks",
"2430": "bunker",
"2440": cte.PENITENTIARY,
"2450": "cemetery building",
"2460": "funeral parlor",
"2470": "crematorium",
"2480": "train station",
"2490": "airport building",
"2500": "building for underground station",
"2510": "building for tramway",
"2520": "building for bus station",
"2530": "shipping terminal",
"2540": "building for recuperation purposes",
"2550": "building for sport purposes",
"2560": "sports hall",
"2570": "building for sports field",
"2580": "swimming baths",
"2590": "indoor swimming pool",
"2600": "sanatorium",
"2610": "zoo building",
"2620": cte.GREEN_HOUSE,
"2630": "botanical show house",
"2640": "bothy",
"2650": "tourist information centre",
"2700": "others",
}
@property
def dictionary(self) -> dict:
return self._dictionary

View File

@ -0,0 +1,32 @@
"""
Dictionaries module for Hft function to hub function
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
"""
import hub.helpers.constants as cte
class HftFunctionToHubFunction:
def __init__(self):
self._dictionary = {
'residential': cte.RESIDENTIAL,
'single family house': cte.SINGLE_FAMILY_HOUSE,
'multifamily house': cte.MULTI_FAMILY_HOUSE,
'hotel': cte.HOTEL,
'hospital': cte.HOSPITAL,
'outpatient': cte.OUT_PATIENT_HEALTH_CARE,
'commercial': cte.SUPERMARKET,
'strip mall': cte.STRIP_MALL,
'warehouse': cte.WAREHOUSE,
'primary school': cte.PRIMARY_SCHOOL,
'secondary school': cte.EDUCATION,
'office': cte.MEDIUM_OFFICE,
'large office': cte.LARGE_OFFICE
}
@property
def dictionary(self) -> dict:
return self._dictionary

View File

@ -0,0 +1,78 @@
"""
Dictionaries module for hub function to nrcan construction function
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
"""
import hub.helpers.constants as cte
class HubFunctionToNrcanConstructionFunction:
def __init__(self):
self._dictionary = {
cte.RESIDENTIAL: 'MidriseApartment',
cte.SINGLE_FAMILY_HOUSE: 'MidriseApartment',
cte.MULTI_FAMILY_HOUSE: 'HighriseApartment',
cte.ROW_HOUSE: 'MidriseApartment',
cte.MID_RISE_APARTMENT: 'MidriseApartment',
cte.HIGH_RISE_APARTMENT: 'HighriseApartment',
cte.OFFICE_AND_ADMINISTRATION: 'MediumOffice',
cte.SMALL_OFFICE: 'SmallOffice',
cte.MEDIUM_OFFICE: 'MediumOffice',
cte.LARGE_OFFICE: 'LargeOffice',
cte.COURTHOUSE: 'MediumOffice',
cte.FIRE_STATION: 'n/a',
cte.PENITENTIARY: 'LargeHotel',
cte.POLICE_STATION: 'n/a',
cte.POST_OFFICE: 'MediumOffice',
cte.LIBRARY: 'MediumOffice',
cte.EDUCATION: 'SecondarySchool',
cte.PRIMARY_SCHOOL: 'PrimarySchool',
cte.PRIMARY_SCHOOL_WITH_SHOWER: 'PrimarySchool',
cte.SECONDARY_SCHOOL: 'SecondarySchool',
cte.UNIVERSITY: 'SecondarySchool',
cte.LABORATORY_AND_RESEARCH_CENTER: 'SecondarySchool',
cte.STAND_ALONE_RETAIL: 'RetailStandalone',
cte.HOSPITAL: 'Hospital',
cte.OUT_PATIENT_HEALTH_CARE: 'Outpatient',
cte.HEALTH_CARE: 'Outpatient',
cte.RETIREMENT_HOME_OR_ORPHANAGE: 'SmallHotel',
cte.COMMERCIAL: 'RetailStripmall',
cte.STRIP_MALL: 'RetailStripmall',
cte.SUPERMARKET: 'RetailStripmall',
cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'RetailStandalone',
cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'RetailStandalone',
cte.RESTAURANT: 'FullServiceRestaurant',
cte.QUICK_SERVICE_RESTAURANT: 'QuickServiceRestaurant',
cte.FULL_SERVICE_RESTAURANT: 'FullServiceRestaurant',
cte.HOTEL: 'SmallHotel',
cte.HOTEL_MEDIUM_CLASS: 'SmallHotel',
cte.SMALL_HOTEL: 'SmallHotel',
cte.LARGE_HOTEL: 'LargeHotel',
cte.DORMITORY: 'SmallHotel',
cte.EVENT_LOCATION: 'n/a',
cte.CONVENTION_CENTER: 'n/a',
cte.HALL: 'n/a',
cte.GREEN_HOUSE: 'n/a',
cte.INDUSTRY: 'n/a',
cte.WORKSHOP: 'n/a',
cte.WAREHOUSE: 'Warehouse',
cte.WAREHOUSE_REFRIGERATED: 'Warehouse',
cte.SPORTS_LOCATION: 'n/a',
cte.SPORTS_ARENA: 'n/a',
cte.GYMNASIUM: 'n/a',
cte.MOTION_PICTURE_THEATRE: 'n/a',
cte.MUSEUM: 'n/a',
cte.PERFORMING_ARTS_THEATRE: 'n/a',
cte.TRANSPORTATION: 'n/a',
cte.AUTOMOTIVE_FACILITY: 'n/a',
cte.PARKING_GARAGE: 'n/a',
cte.RELIGIOUS: 'n/a',
cte.NON_HEATED: 'n/a'
}
@property
def dictionary(self) -> dict:
return self._dictionary

View File

@ -0,0 +1,78 @@
"""
Dictionaries module for hub function to NREL construction function
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
"""
import hub.helpers.constants as cte
class HubFunctionToNrelConstructionFunction:
def __init__(self):
self._dictionary = {
cte.RESIDENTIAL: 'residential',
cte.SINGLE_FAMILY_HOUSE: 'residential',
cte.MULTI_FAMILY_HOUSE: 'midrise apartment',
cte.ROW_HOUSE: 'midrise apartment',
cte.MID_RISE_APARTMENT: 'midrise apartment',
cte.HIGH_RISE_APARTMENT: 'high-rise apartment',
cte.OFFICE_AND_ADMINISTRATION: 'medium office',
cte.SMALL_OFFICE: 'small office',
cte.MEDIUM_OFFICE: 'medium office',
cte.LARGE_OFFICE: 'large office',
cte.COURTHOUSE: 'medium office',
cte.FIRE_STATION: 'n/a',
cte.PENITENTIARY: 'large hotel',
cte.POLICE_STATION: 'n/a',
cte.POST_OFFICE: 'medium office',
cte.LIBRARY: 'medium office',
cte.EDUCATION: 'secondary school',
cte.PRIMARY_SCHOOL: 'primary school',
cte.PRIMARY_SCHOOL_WITH_SHOWER: 'primary school',
cte.SECONDARY_SCHOOL: 'secondary school',
cte.UNIVERSITY: 'secondary school',
cte.LABORATORY_AND_RESEARCH_CENTER: 'secondary school',
cte.STAND_ALONE_RETAIL: 'stand-alone retail',
cte.HOSPITAL: 'hospital',
cte.OUT_PATIENT_HEALTH_CARE: 'outpatient healthcare',
cte.HEALTH_CARE: 'outpatient healthcare',
cte.RETIREMENT_HOME_OR_ORPHANAGE: 'small hotel',
cte.COMMERCIAL: 'strip mall',
cte.STRIP_MALL: 'strip mall',
cte.SUPERMARKET: 'supermarket',
cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'stand-alone retail',
cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'stand-alone retail',
cte.RESTAURANT: 'full service restaurant',
cte.QUICK_SERVICE_RESTAURANT: 'quick service restaurant',
cte.FULL_SERVICE_RESTAURANT: 'full service restaurant',
cte.HOTEL: 'small hotel',
cte.HOTEL_MEDIUM_CLASS: 'small hotel',
cte.SMALL_HOTEL: 'small hotel',
cte.LARGE_HOTEL: 'large hotel',
cte.DORMITORY: 'small hotel',
cte.EVENT_LOCATION: 'n/a',
cte.CONVENTION_CENTER: 'n/a',
cte.HALL: 'n/a',
cte.GREEN_HOUSE: 'n/a',
cte.INDUSTRY: 'n/a',
cte.WORKSHOP: 'n/a',
cte.WAREHOUSE: 'warehouse',
cte.WAREHOUSE_REFRIGERATED: 'warehouse',
cte.SPORTS_LOCATION: 'n/a',
cte.SPORTS_ARENA: 'n/a',
cte.GYMNASIUM: 'n/a',
cte.MOTION_PICTURE_THEATRE: 'n/a',
cte.MUSEUM: 'n/a',
cte.PERFORMING_ARTS_THEATRE: 'n/a',
cte.TRANSPORTATION: 'n/a',
cte.AUTOMOTIVE_FACILITY: 'n/aquebec_to_hub',
cte.PARKING_GARAGE: 'n/a',
cte.RELIGIOUS: 'n/a',
cte.NON_HEATED: 'n/a'
}
@property
def dictionary(self) -> dict:
return self._dictionary

View File

@ -0,0 +1,78 @@
"""
Dictionaries module for hub usage to Comnet usage
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
"""
import hub.helpers.constants as cte
class HubUsageToComnetUsage:
def __init__(self):
self._dictionary = {
cte.RESIDENTIAL: 'BA Multifamily',
cte.SINGLE_FAMILY_HOUSE: 'BA Multifamily',
cte.MULTI_FAMILY_HOUSE: 'BA Multifamily',
cte.ROW_HOUSE: 'BA Multifamily',
cte.MID_RISE_APARTMENT: 'BA Multifamily',
cte.HIGH_RISE_APARTMENT: 'BA Multifamily',
cte.OFFICE_AND_ADMINISTRATION: 'BA Office',
cte.SMALL_OFFICE: 'BA Office',
cte.MEDIUM_OFFICE: 'BA Office',
cte.LARGE_OFFICE: 'BA Office',
cte.COURTHOUSE: 'BA Courthouse',
cte.FIRE_STATION: 'BA Fire Station',
cte.PENITENTIARY: 'BA Penitentiary',
cte.POLICE_STATION: 'BA Police Station',
cte.POST_OFFICE: 'BA Post Office',
cte.LIBRARY: 'BA Library',
cte.EDUCATION: 'BA School/University',
cte.PRIMARY_SCHOOL: 'BA School/University',
cte.PRIMARY_SCHOOL_WITH_SHOWER: 'BA School/University',
cte.SECONDARY_SCHOOL: 'BA School/University',
cte.UNIVERSITY: 'BA School/University',
cte.LABORATORY_AND_RESEARCH_CENTER: 'BA School/University',
cte.STAND_ALONE_RETAIL: 'BA Retail',
cte.HOSPITAL: 'BA Hospital',
cte.OUT_PATIENT_HEALTH_CARE: 'BA Healthcare Clinic',
cte.HEALTH_CARE: 'BA Healthcare Clinic',
cte.RETIREMENT_HOME_OR_ORPHANAGE: 'BA Healthcare Clinic',
cte.COMMERCIAL: 'BA Retail',
cte.STRIP_MALL: 'BA Retail',
cte.SUPERMARKET: 'BA Retail',
cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'BA Retail',
cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'BA Retail',
cte.RESTAURANT: 'BA Dining: Bar Lounge/Leisure',
cte.QUICK_SERVICE_RESTAURANT: 'BA Dining: Cafeteria/Fast Food',
cte.FULL_SERVICE_RESTAURANT: 'BA Dining: Bar Lounge/Leisure',
cte.HOTEL: 'BA Hotel',
cte.HOTEL_MEDIUM_CLASS: 'BA Motel',
cte.SMALL_HOTEL: 'BA Motel',
cte.LARGE_HOTEL: 'BA Hotel',
cte.DORMITORY: 'BA Dormitory',
cte.EVENT_LOCATION: 'BA Convention Center',
cte.CONVENTION_CENTER: 'BA Convention Center',
cte.HALL: 'BA Town Hall',
cte.GREEN_HOUSE: 'n/a',
cte.INDUSTRY: 'BA Manufacturing Facility',
cte.WORKSHOP: 'BA Workshop',
cte.WAREHOUSE: 'BA Warehouse',
cte.WAREHOUSE_REFRIGERATED: 'BA Warehouse',
cte.SPORTS_LOCATION: 'BA Exercise Center',
cte.SPORTS_ARENA: 'BA Sports Arena',
cte.GYMNASIUM: 'BA Gymnasium',
cte.MOTION_PICTURE_THEATRE: 'BA Motion Picture Theater',
cte.MUSEUM: 'BA Museum',
cte.PERFORMING_ARTS_THEATRE: 'BA Performing Arts Theater',
cte.TRANSPORTATION: 'BA Transportation',
cte.AUTOMOTIVE_FACILITY: 'BA Automotive Facility',
cte.PARKING_GARAGE: 'BA Parking Garage',
cte.RELIGIOUS: 'BA Religious Building',
cte.NON_HEATED: 'n/a'
}
@property
def dictionary(self) -> dict:
return self._dictionary

View File

@ -0,0 +1,78 @@
"""
Dictionaries module for hub usage to Hft usage
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
"""
import hub.helpers.constants as cte
class HubUsageToHftUsage:
def __init__(self):
self._dictionary = {
cte.RESIDENTIAL: 'residential',
cte.SINGLE_FAMILY_HOUSE: 'single family house',
cte.MULTI_FAMILY_HOUSE: 'multifamily house',
cte.ROW_HOUSE: 'single family house',
cte.MID_RISE_APARTMENT: 'multifamily house',
cte.HIGH_RISE_APARTMENT: 'multifamily house',
cte.OFFICE_AND_ADMINISTRATION: 'office and administration',
cte.SMALL_OFFICE: 'office and administration',
cte.MEDIUM_OFFICE: 'office and administration',
cte.LARGE_OFFICE: 'office and administration',
cte.COURTHOUSE: 'office and administration',
cte.FIRE_STATION: 'office and administration',
cte.PENITENTIARY: 'school with shower',
cte.POLICE_STATION: 'office and administration',
cte.POST_OFFICE: 'office and administration',
cte.LIBRARY: 'office and administration',
cte.EDUCATION: 'education',
cte.PRIMARY_SCHOOL: 'school without shower',
cte.PRIMARY_SCHOOL_WITH_SHOWER: 'school with shower',
cte.SECONDARY_SCHOOL: 'education',
cte.UNIVERSITY: 'education',
cte.LABORATORY_AND_RESEARCH_CENTER: 'laboratory and research centers',
cte.STAND_ALONE_RETAIL: 'retail',
cte.HOSPITAL: 'health care',
cte.OUT_PATIENT_HEALTH_CARE: 'health care',
cte.HEALTH_CARE: 'health care',
cte.RETIREMENT_HOME_OR_ORPHANAGE: 'Home for the aged or orphanage',
cte.COMMERCIAL: 'retail',
cte.STRIP_MALL: 'retail',
cte.SUPERMARKET: 'retail shop / refrigerated food',
cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'retail',
cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'retail shop / refrigerated food',
cte.RESTAURANT: 'restaurant',
cte.QUICK_SERVICE_RESTAURANT: 'restaurant',
cte.FULL_SERVICE_RESTAURANT: 'restaurant',
cte.HOTEL: 'hotel',
cte.HOTEL_MEDIUM_CLASS: 'hotel (Medium-class)',
cte.SMALL_HOTEL: 'hotel',
cte.LARGE_HOTEL: 'hotel',
cte.DORMITORY: 'dormitory',
cte.EVENT_LOCATION: 'event location',
cte.CONVENTION_CENTER: 'event location',
cte.HALL: 'hall',
cte.GREEN_HOUSE: 'green house',
cte.INDUSTRY: 'industry',
cte.WORKSHOP: 'industry',
cte.WAREHOUSE: 'industry',
cte.WAREHOUSE_REFRIGERATED: 'industry',
cte.SPORTS_LOCATION: 'sport location',
cte.SPORTS_ARENA: 'sport location',
cte.GYMNASIUM: 'sport location',
cte.MOTION_PICTURE_THEATRE: 'event location',
cte.MUSEUM: 'event location',
cte.PERFORMING_ARTS_THEATRE: 'event location',
cte.TRANSPORTATION: 'n/a',
cte.AUTOMOTIVE_FACILITY: 'n/a',
cte.PARKING_GARAGE: 'n/a',
cte.RELIGIOUS: 'event location',
cte.NON_HEATED: 'non-heated'
}
@property
def dictionary(self) -> dict:
return self._dictionary

View File

@ -0,0 +1,78 @@
"""
Dictionaries module for hub usage to NRCAN usage
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
"""
import hub.helpers.constants as cte
class HubUsageToNrcanUsage:
def __init__(self):
self._dictionary = {
cte.RESIDENTIAL: 'Multi-unit residential building',
cte.SINGLE_FAMILY_HOUSE: 'Multi-unit residential building',
cte.MULTI_FAMILY_HOUSE: 'Multi-unit residential building',
cte.ROW_HOUSE: 'Multi-unit residential building',
cte.MID_RISE_APARTMENT: 'Multi-unit residential building',
cte.HIGH_RISE_APARTMENT: 'Multi-unit residential building',
cte.OFFICE_AND_ADMINISTRATION: 'Office',
cte.SMALL_OFFICE: 'Office',
cte.MEDIUM_OFFICE: 'Office',
cte.LARGE_OFFICE: 'Office',
cte.COURTHOUSE: 'Courthouse',
cte.FIRE_STATION: 'Fire station',
cte.PENITENTIARY: 'Penitentiary',
cte.POLICE_STATION: 'Police station',
cte.POST_OFFICE: 'Post office',
cte.LIBRARY: 'Library',
cte.EDUCATION: 'School/university',
cte.PRIMARY_SCHOOL: 'School/university',
cte.PRIMARY_SCHOOL_WITH_SHOWER: 'School/university',
cte.SECONDARY_SCHOOL: 'School/university',
cte.UNIVERSITY: 'School/university',
cte.LABORATORY_AND_RESEARCH_CENTER: 'School/university',
cte.STAND_ALONE_RETAIL: 'Retail',
cte.HOSPITAL: 'Hospital',
cte.OUT_PATIENT_HEALTH_CARE: 'Health-care clinic',
cte.HEALTH_CARE: 'Health-care clinic',
cte.RETIREMENT_HOME_OR_ORPHANAGE: 'Health-care clinic',
cte.COMMERCIAL: 'Retail',
cte.STRIP_MALL: 'Retail',
cte.SUPERMARKET: 'Retail',
cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'Retail',
cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'Retail',
cte.RESTAURANT: 'Dining - bar/lounge',
cte.QUICK_SERVICE_RESTAURANT: 'Dining - cafeteria',
cte.FULL_SERVICE_RESTAURANT: 'Dining - bar/lounge',
cte.HOTEL: 'Hotel',
cte.HOTEL_MEDIUM_CLASS: 'Motel',
cte.SMALL_HOTEL: 'Motel',
cte.LARGE_HOTEL: 'Hotel',
cte.DORMITORY: 'Dormitory',
cte.EVENT_LOCATION: 'Convention centre',
cte.CONVENTION_CENTER: 'Convention centre',
cte.HALL: 'Town hall',
cte.GREEN_HOUSE: 'n/a',
cte.INDUSTRY: 'Manufacturing facility',
cte.WORKSHOP: 'Workshop',
cte.WAREHOUSE: 'Warehouse',
cte.WAREHOUSE_REFRIGERATED: 'Warehouse - refrigerated',
cte.SPORTS_LOCATION: 'Exercise centre',
cte.SPORTS_ARENA: 'Sports arena',
cte.GYMNASIUM: 'Gymnasium',
cte.MOTION_PICTURE_THEATRE: 'Motion picture theatre',
cte.MUSEUM: 'Museum',
cte.PERFORMING_ARTS_THEATRE: 'Performing arts theatre',
cte.TRANSPORTATION: 'Transportation',
cte.AUTOMOTIVE_FACILITY: 'Automotive facility',
cte.PARKING_GARAGE: 'Parking garage',
cte.RELIGIOUS: 'Religious',
cte.NON_HEATED: 'n/a'
}
@property
def dictionary(self) -> dict:
return self._dictionary

View File

@ -0,0 +1,557 @@
"""
Dictionaries module for Montreal function to hub function
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
"""
import hub.helpers.constants as cte
class MontrealFunctionToHubFunction:
# Todo: "office" "Mausolée" and "hotel/motel" need to be replaced for a constant value.
def __init__(self):
self._dictionary = {
"Administration publique municipale et régionale": "Office",
"Administration publique provinciale": "Office",
"Agence de voyages ou d'expéditions": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Aiguillage et cour de triage de chemins de fer": cte.WAREHOUSE,
"Amphithéâtre et auditorium": cte.EVENT_LOCATION,
"Archives (incluant cinémathèquevidéothèque)": cte.EVENT_LOCATION,
"Aréna et activités connexes (patinage sur glace)": cte.SPORTS_LOCATION,
"Association civiquesociale et fraternelle": cte.OFFICE_AND_ADMINISTRATION,
"Associationunion ou coop d'épargne et de prêt (inclus caisses populaires locales)": cte.OFFICE_AND_ADMINISTRATION,
"Atelier d'artiste": cte.WAREHOUSE,
"Atelier d'artiste ou d'artisan": cte.WAREHOUSE,
"Atelier d'usinage": cte.WAREHOUSE,
"Atelier de mécanicien-dentiste": cte.WAREHOUSE,
"Auberge ou gîte touristique (Hôtel à caractère familiald'au plus 3 étages en hauteur de bâtiment)": cte.SMALL_HOTEL,
"Autoroute": cte.WAREHOUSE,
"Autres activités agricoles": cte.INDUSTRY,
"Autres activités culturelles": cte.EVENT_LOCATION,
"Autres activités d'hébergement": cte.MULTI_FAMILY_HOUSE,
"Autres activités d'impression commerciale": cte.WAREHOUSE,
"Autres activités de la restauration": cte.WAREHOUSE,
"Autres activités de récupération et de triage": cte.WAREHOUSE,
"Autres activités de vente au détail (inclus les kiosques d'autres choses que vêtements et accessoires de vêtements)": cte.STAND_ALONE_RETAIL,
"Autres activités de vente au détail de produits de l'alimentation": cte.STAND_ALONE_RETAIL,
"Autres activités de vente au détail de vêtements comme les accessoires": cte.STAND_ALONE_RETAIL,
"Autres activités de vente au détail reliées aux automobilesaux embarcationsaux avions et à leurs accessoires": cte.STAND_ALONE_RETAIL,
"Autres activités de vente en gros": cte.WAREHOUSE,
"Autres activités minières et extraction de carrières de minerais non métalliques (sauf le pétrole)": cte.INDUSTRY,
"Autres activités nautiques": cte.WAREHOUSE,
"Autres activités religieuses": cte.OFFICE_AND_ADMINISTRATION,
"Autres activités reliées au transport de matériaux par camion": cte.WAREHOUSE,
"Autres activités reliées au transport par autobus": cte.WAREHOUSE,
"Autres activités reliées au transport par chemin de fer": cte.WAREHOUSE,
"Autres activités sportives (inclus centres de tir à l'arc)": cte.SPORTS_LOCATION,
"Autres aménagements d'assemblées publiques": cte.OFFICE_AND_ADMINISTRATION,
"Autres aménagements publics pour différentes activités": cte.OFFICE_AND_ADMINISTRATION,
"Autres aéroports": cte.WAREHOUSE,
"Autres bases et réserves militaires": cte.WAREHOUSE,
"Autres centres de recherche": cte.SECONDARY_SCHOOL,
"Autres centres de services sociaux ou bureaux de travailleurs sociaux": cte.OFFICE_AND_ADMINISTRATION,
"Autres centres et réseaux de télévision et de radiodiffusion (système combiné)": "Office",
"Autres entreposages": cte.WAREHOUSE,
"Autres espaces de plancher inoccupé": cte.WAREHOUSE,
"Autres espaces de terrain et étendues d'eau inexploités": cte.WAREHOUSE,
"Autres expositions d'objets culturels": cte.EVENT_LOCATION,
"Autres immeubles résidentiels": cte.MID_RISE_APARTMENT,
"Autres industries d'appareils d'éclairage": cte.INDUSTRY,
"Autres industries de boissons": cte.INDUSTRY,
"Autres industries de la fabrication d'éléments de charpentes métalliques": cte.INDUSTRY,
"Autres industries de la fonte et de l'affinage de métaux non-ferreux": cte.INDUSTRY,
"Autres industries de la machinerie industrielle et de l'équipement industriel": cte.INDUSTRY,
"Autres industries de pièces et d'accessoires pour véhicules automobiles": cte.INDUSTRY,
"Autres industries de produits alimentaires": cte.INDUSTRY,
"Autres industries de produits alimentaires à base de fruits et de légumes": cte.INDUSTRY,
"Autres industries de produits chimiques": cte.INDUSTRY,
"Autres industries de produits du pétrole et du charbon": cte.INDUSTRY,
"Autres industries de produits en béton": cte.INDUSTRY,
"Autres industries de produits en caoutchouc": cte.INDUSTRY,
"Autres industries de produits en fil métallique": cte.INDUSTRY,
"Autres industries de produits en plastique": cte.INDUSTRY,
"Autres industries de produits manufacturés": cte.INDUSTRY,
"Autres industries de produits métalliques d'ornement et d'architecture": cte.INDUSTRY,
"Autres industries de produits métalliques divers": cte.INDUSTRY,
"Autres industries de produits textiles": cte.INDUSTRY,
"Autres industries de produits électriques.": cte.INDUSTRY,
"Autres industries de vêtements coupés cousus pour femmes et filles": cte.INDUSTRY,
"Autres industries du bois": cte.INDUSTRY,
"Autres industries du laminagedu moulage et de l'extrusion de métaux non-ferreux": cte.INDUSTRY,
"Autres industries du matériel de transport": cte.INDUSTRY,
"Autres industries du matériel scientifique et professionnel": cte.INDUSTRY,
"Autres industries du matériel électrique d'usage industriel": cte.INDUSTRY,
"Autres industries du matériel électronique et de communication": cte.INDUSTRY,
"Autres industries du meuble de bureau": cte.INDUSTRY,
"Autres industries du meuble et d'articles d'ameublement": cte.INDUSTRY,
"Autres industries du meuble résidentiel.": cte.INDUSTRY,
"Autres industries du papier": cte.INDUSTRY,
"Autres industries sidérurgiques": cte.INDUSTRY,
"Autres infrastructures de transport maritime": cte.INDUSTRY,
"Autres installations inhérentes aux ordures": cte.WAREHOUSE,
"Autres installations pour les sports": cte.SPORTS_LOCATION,
"Autres institutions de formation spécialisée (inclus écoles de langues de coutured'arts martiaux de combats et autres)": cte.SECONDARY_SCHOOL,
"Autres lieux d'assemblée pour les loisirs": cte.OFFICE_AND_ADMINISTRATION,
"Autres locaux de groupes": cte.OFFICE_AND_ADMINISTRATION,
"Autres maisons d'institutions religieuses": cte.OFFICE_AND_ADMINISTRATION,
"Autres maisons et locaux fraternels": cte.OFFICE_AND_ADMINISTRATION,
"Autres maisons pour personnes retraitées": cte.OFFICE_AND_ADMINISTRATION,
"Autres parcs": cte.WAREHOUSE,
"Autres routes et voies publiques": "Office",
"Autres résidences d'étudiants": "Office",
"Autres résidences provisoires": "Office",
"Autres services connexes aux valeurs mobilières et aux marchandises": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Autres services d'affaires": "Office",
"Autres services d'aqueduc et d'irrigation": cte.WAREHOUSE,
"Autres services de construction de bâtiments": cte.WAREHOUSE,
"Autres services de génie civil (entrepreneur général)": cte.WAREHOUSE,
"Autres services de l'automobile": cte.WAREHOUSE,
"Autres services de location (sauf entreposage)": cte.WAREHOUSE,
"Autres services de nettoyage": cte.WAREHOUSE,
"Autres services de réparation et d'entretien d'articles personnels et ménagers": cte.STAND_ALONE_RETAIL,
"Autres services de soins thérapeutiques": cte.OUT_PATIENT_HEALTH_CARE,
"Autres services de travaux de construction spécialisés": cte.WAREHOUSE,
"Autres services de travaux de finition de bâtiment (entrepreneur spécialisé)": cte.WAREHOUSE,
"Autres services de télécommunications": cte.STAND_ALONE_RETAIL,
"Autres services divers": cte.WAREHOUSE,
"Autres services du pétrole": cte.WAREHOUSE,
"Autres services gouvernementaux": cte.OFFICE_AND_ADMINISTRATION,
"Autres services immobiliersfinanciers et d'assurance": cte.OFFICE_AND_ADMINISTRATION,
"Autres services médicaux et de santé": cte.OUT_PATIENT_HEALTH_CARE,
"Autres services personnels": cte.OUT_PATIENT_HEALTH_CARE,
"Autres services pour animaux domestiques": cte.OUT_PATIENT_HEALTH_CARE,
"Autres services pour le transport": cte.WAREHOUSE,
"Autres services pour les bâtiments": cte.WAREHOUSE,
"Autres services professionnels": cte.OFFICE_AND_ADMINISTRATION,
"Autres services publics (infrastructure)": cte.WAREHOUSE,
"Autres services reliés à la foresterie": cte.WAREHOUSE,
"Autres terrains de jeux et pistes athlétiques": cte.SPORTS_LOCATION,
"Autres transports par avion (infrastructure)": cte.WAREHOUSE,
"Autres transports par véhicule automobile": cte.WAREHOUSE,
"Autres transportscommunications et services publics (infrastructure)": cte.GREEN_HOUSE,
"Autres types de production végétale": cte.GREEN_HOUSE,
"Autres ventes au détail de marchandises en général": cte.STAND_ALONE_RETAIL,
"Autres établissements avec service complet ou restreint": cte.STAND_ALONE_RETAIL,
"Autres établissements de débits de boissons alcoolisées": cte.STAND_ALONE_RETAIL,
"Aéroport et aérodrome": cte.EVENT_LOCATION,
"Bar à crème glacée": cte.QUICK_SERVICE_RESTAURANT,
"Bar à spectacles": cte.FULL_SERVICE_RESTAURANT,
"Bibliothèque": cte.OFFICE_AND_ADMINISTRATION,
"Bureau de poste": cte.OFFICE_AND_ADMINISTRATION,
"Bâtiment incendié et inutilisable": cte.NON_HEATED,
"C.E.G.E.P. (collège d'enseignement général et professionnel)": cte.SECONDARY_SCHOOL,
"Centre commercial de quartier (15 à 44 magasins)": cte.STRIP_MALL,
"Centre commercial de voisinage (14 magasins et moins)": cte.STAND_ALONE_RETAIL,
"Centre commercial local (45 à 99 magasins)": cte.STRIP_MALL,
"Centre commercial régional (100 à 199 magasins)": cte.STRIP_MALL,
"Centre commercial super régional (200 magasins et plus)": cte.STRIP_MALL,
"Centre communautaire ou de quartier (inclus Centre diocésain)": cte.OFFICE_AND_ADMINISTRATION,
"Centre d'accueil ou établissement curatif (inclus centre de réadaptation pour handicapés physiques et mentaux)": cte.OUT_PATIENT_HEALTH_CARE,
"Centre d'appels téléphoniques": "Office",
"Centre d'entraide et de ressources communautaires (inclus ressources d'hébergement de meubles et d'alimentation)": cte.OUT_PATIENT_HEALTH_CARE,
"Centre d'entreposage de produits pétroliers (pétrole brutgaz pétrole liquéfiémazout domestique et autres produits raffinés)": cte.WAREHOUSE,
"Centre d'entreposage du gaz (avant distrib.aux consommateurs)": cte.WAREHOUSE,
"Centre de distribution ou d'expédition de marchandises diverses": cte.WAREHOUSE,
"Centre de recherche d'activités émergentes (inclus technologies langagières et la photonique)": cte.SECONDARY_SCHOOL,
"Centre de santé (inclus saunas spas et bains thérapeutiques ou turcs)": cte.OUT_PATIENT_HEALTH_CARE,
"Centre de services sociaux (C.S.S. et C.R.S.S.S.)": cte.OUT_PATIENT_HEALTH_CARE,
"Centre de transfert ou d'entreposage de déchets dangereux": cte.WAREHOUSE,
"Centre de tri postal": cte.WAREHOUSE,
"Centre de vérification technique d'automobiles et d'estimation": cte.WAREHOUSE,
"Centre local de services communautaires (C.L.S.C.)": cte.OFFICE_AND_ADMINISTRATION,
"Centre militaire de transport et d'entreposage": cte.WAREHOUSE,
"Centre récréatif en général (activités récréatives diversifiées pour tous groupes d'âge)": cte.EVENT_LOCATION,
"Centre sportif multidisciplinaire (couvert).": cte.SPORTS_LOCATION,
"Chalet ou maison de villégiature": cte.SINGLE_FAMILY_HOUSE,
"Chemin de fer (sauf train touristiqueaiguillage et cour de triage)": cte.WAREHOUSE,
"Cimetière": cte.WAREHOUSE,
"Cinéma": cte.EVENT_LOCATION,
"Clinique médicale (cabinet de médecins généralistes)": cte.OUT_PATIENT_HEALTH_CARE,
"Commission scolaire": cte.OFFICE_AND_ADMINISTRATION,
"Conserveriemarinagesaumurage et séchage de fruits et de légumes": cte.WAREHOUSE,
"Construction d'immeubles pour revente": cte.WAREHOUSE,
"Couvent": cte.EVENT_LOCATION,
"Dépanneur (sans vente d'essence)": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Entreposage de tout genre": cte.WAREHOUSE,
"Entreposage du mobilier et d'appareils ménagersincluant les mini-entrepôts": cte.WAREHOUSE,
"Entreposage en vrac à l'extérieur": cte.WAREHOUSE,
"Entreposage frigorifique (sauf les armoires frigorifiques)": cte.WAREHOUSE,
"Entreprise d'excavationde nivellementde défrichage et installation de fosses septiques": cte.WAREHOUSE,
"Entrepôt pour le transport par camion": cte.WAREHOUSE,
"Entretien et équipement de chemins de fer": cte.WAREHOUSE,
"Espace de plancher inoccupé dont l'usage serait commercial autre": cte.NON_HEATED,
"Espace de plancher inoccupé dont l'usage serait industriel": cte.NON_HEATED,
"Espace de plancher inoccupé dont l'usage serait pour des fins culturelles": cte.NON_HEATED,
"Espace de plancher inoccupé dont l'usage serait pour services publics": cte.NON_HEATED,
"Espace de rangement (condo non résidentiel)": cte.NON_HEATED,
"Espace de rangement (condo)": cte.NON_HEATED,
"Espace de terrain non aménagé et non exploité (sauf l'exploitation non commerciale de la forêt)": cte.NON_HEATED,
"Espace pour le séchage des boues provenant de l'usine d'épuration": cte.WAREHOUSE,
"Fabrication de crème glacée et de desserts congelés": cte.INDUSTRY,
"Fondations et organismes de charité": cte.OFFICE_AND_ADMINISTRATION,
"Galerie d'art": cte.EVENT_LOCATION,
"Garage d'autobus et équipement d'entretien": cte.WAREHOUSE,
"Garage de stationnement pour automobiles (infrastructure)": cte.WAREHOUSE,
"Garage de stationnement pour véhicules lourds (Infrastructure)": cte.WAREHOUSE,
"Garage et équipement d'entretien pour le transport par camion (incluant garages municipaux)": cte.WAREHOUSE,
"Gare d'autobus pour passagers": cte.WAREHOUSE,
"Gare de chemins de fer": cte.WAREHOUSE,
"Gymnase et formation athlétique": cte.SPORTS_LOCATION,
"Hangar à avion": cte.WAREHOUSE,
"Hôtel (incluant les hôtels-motels)": "Hotel/Motel",
"Hôtel résidentiel": "Hotel/Motel",
"Immeuble commercial": cte.STAND_ALONE_RETAIL,
"Immeuble non résidentiel en construction": "Office",
"Immeuble résidentiel en construction": cte.RESIDENTIAL,
"Immeuble à bureaux": "Office",
"Immeuble à temps partagé («time share») Propriété ou copropriété ou groupe d'usufruitier ont chacun droit de jouissancepériodique et successif.": "Office",
"Incinérateur": cte.INDUSTRY,
"Industrie d'accessoires vestimentaires et d'autres vêtements": cte.INDUSTRY,
"Industrie d'alcools destinés à la consommation (distillerie)": cte.INDUSTRY,
"Industrie d'appareils d'éclairage (sauf ampoules et tubes)": cte.INDUSTRY,
"Industrie d'appareils orthopédiques et chirurgicaux": cte.INDUSTRY,
"Industrie d'armoires de placards de cuisine et de coiffeuses de salle de bains en bois": cte.INDUSTRY,
"Industrie d'articles de maison en textile et d'articles d'hygiène en textile": cte.INDUSTRY,
"Industrie d'articles de sport et d'athlétisme": cte.INDUSTRY,
"Industrie d'assaisonnements et de vinaigrettes": cte.INDUSTRY,
"Industrie d'autres produits de boulangerie et de pâtisseries": cte.INDUSTRY,
"Industrie d'autres vêtements coupés cousus pour hommes et garçons": cte.INDUSTRY,
"Industrie d'engrais chimique et d'engrais composé": cte.INDUSTRY,
"Industrie d'enseignes au néon (excluant les enseignes en bois) éclairage interne": cte.INDUSTRY,
"Industrie d'équipements de télécommunication": cte.INDUSTRY,
"Industrie de bas et de chaussettes": cte.INDUSTRY,
"Industrie de boissons gazeuses": cte.INDUSTRY,
"Industrie de boîtes en carton ondulé et en carton compact": cte.INDUSTRY,
"Industrie de boîtes pliantes et rigides": cte.INDUSTRY,
"Industrie de carrosseries de véhicules automobiles": cte.INDUSTRY,
"Industrie de chaudièresd'échangeurs de chaleur et de plaques métalliques": cte.INDUSTRY,
"Industrie de contenants en plastique (sauf en mousse)": cte.INDUSTRY,
"Industrie de contreplaqués en bois": cte.INDUSTRY,
"Industrie de fabrication de gaz industriel": cte.INDUSTRY,
"Industrie de fils et de câbles électriques": cte.INDUSTRY,
"Industrie de filés et de tissus tissés (coton)": cte.INDUSTRY,
"Industrie de garnitures et de raccords de plomberie en métal": cte.INDUSTRY,
"Industrie de jouets et de jeux": cte.INDUSTRY,
"Industrie de l'abattage et du conditionnement de la viande (sauf la volaille et le petit gibier)": cte.INDUSTRY,
"Industrie de l'abattage et du conditionnement de la volaille et du petit gibier": cte.INDUSTRY,
"Industrie de l'impression de formulaires commerciaux": cte.INDUSTRY,
"Industrie de l'équipement de manutention": cte.INDUSTRY,
"Industrie de l'étirage de l'extrusion et alliage de l'aluminiumfabriqué à partir d'aluminium acheté": cte.INDUSTRY,
"Industrie de la bijouterie et de l'orfèvrerie (sauf l'affinage secondaire de métaux précieux)": cte.INDUSTRY,
"Industrie de la bière": cte.INDUSTRY,
"Industrie de la chaussure": cte.INDUSTRY,
"Industrie de la confection à forfait de vêtements pour femmes et filles": cte.INDUSTRY,
"Industrie de la construction et de la réparation de navires": cte.INDUSTRY,
"Industrie de la fabrication de supports d'enregistrement de la reproduction du son et des instruments de musique": cte.INDUSTRY,
"Industrie de la glace": cte.INDUSTRY,
"Industrie de la machinerie pour la construction et du matériel d'entretien": cte.INDUSTRY,
"Industrie de la préparation et du conditionnement de poissons et de fruits de mer": cte.INDUSTRY,
"Industrie de la quincaillerie de base": cte.INDUSTRY,
"Industrie de la transformation de la viande et de la fonte des graisses animales": cte.INDUSTRY,
"Industrie de la tôlerie pour ventilation": cte.INDUSTRY,
"Industrie de lampes électriques (ampoules et tubes)": cte.INDUSTRY,
"Industrie de moteurs et de pièces de moteurs de véhicules automobiles": cte.INDUSTRY,
"Industrie de mélange de farine et de pâte": cte.INDUSTRY,
"Industrie de peinturede teinture et de vernis": cte.INDUSTRY,
"Industrie de pellicules et de feuilles non renforcées en plastique": cte.INDUSTRY,
"Industrie de pièces en plastique pour véhicules automobiles": cte.INDUSTRY,
"Industrie de pièces et de composantes électroniques": cte.INDUSTRY,
"Industrie de pneus et de chambres à air": cte.INDUSTRY,
"Industrie de portes et de fenêtres en métal": cte.INDUSTRY,
"Industrie de portes et fenêtres en plastique": cte.INDUSTRY,
"Industrie de produits chimiques inorganiques d'usage industriel": cte.INDUSTRY,
"Industrie de produits d'architecture en plastique": cte.INDUSTRY,
"Industrie de produits de boulangerie commerciale de produits de boulangerie congelés et de pâtisseries": cte.INDUSTRY,
"Industrie de produits de toilette": cte.INDUSTRY,
"Industrie de produits en pierre": cte.INDUSTRY,
"Industrie de produits en plastique stratifié sous pression ou renforcé": cte.INDUSTRY,
"Industrie de produits en verre fabriqué à partir de verre acheté": cte.INDUSTRY,
"Industrie de produits pharmaceutiques et de médicaments": cte.INDUSTRY,
"Industrie de produits pétrochimiques": cte.INDUSTRY,
"Industrie de produits pétroliers raffinés (sauf les huiles de graissage et les graisses lubrifiantes)": cte.INDUSTRY,
"Industrie de pâtes alimentaires sèches": cte.INDUSTRY,
"Industrie de récipients et de boîtes en métal": cte.INDUSTRY,
"Industrie de résines synthétiques et de caoutchouc synthétique": cte.INDUSTRY,
"Industrie de sacs et de poches en matière textile": cte.INDUSTRY,
"Industrie de sacs et de sachets en plastique": cte.INDUSTRY,
"Industrie de savons et de détachants pour le nettoyage": cte.INDUSTRY,
"Industrie de sommiers et de matelas": cte.INDUSTRY,
"Industrie de soupapes en métal": cte.INDUSTRY,
"Industrie de tapis carpettes et moquettes": cte.INDUSTRY,
"Industrie de tous les autres produits divers en bois": cte.INDUSTRY,
"Industrie de tous les autres produits en papier transformé (sauf pour le bureau)": cte.INDUSTRY,
"Industrie de ventilateursde soufflantes et de purificateurs d'air industriels et commerciaux": cte.INDUSTRY,
"Industrie de vêtements de sport pour femmes et filles": cte.INDUSTRY,
"Industrie de vêtements professionnels coupés cousus": cte.INDUSTRY,
"Industrie des pièces et accessoires d'aéronefs (incluant avions et hélicoptères)": cte.INDUSTRY,
"Industrie du béton préparé": cte.INDUSTRY,
"Industrie du cannabis": cte.INDUSTRY,
"Industrie du ciment": cte.INDUSTRY,
"Industrie du clichagede la composition de la reliure et de la lithographie": cte.INDUSTRY,
"Industrie du fromage": cte.INDUSTRY,
"Industrie du lait de consommation": cte.INDUSTRY,
"Industrie du laminagede l'étirage et de l'extrusion du cuivre et de ses alliages": cte.INDUSTRY,
"Industrie du matériel de chauffage et du matériel de réfrigération commerciale": cte.INDUSTRY,
"Industrie du matériel de transport": cte.INDUSTRY,
"Industrie du matériel ferroviaire roulant": cte.INDUSTRY,
"Industrie du matériel électrique de communication et de protection": cte.INDUSTRY,
"Industrie du meuble de maison en bois": cte.INDUSTRY,
"Industrie du meuble et d'articles d'ameublement pour hôtelsrestaurants et institutions": cte.INDUSTRY,
"Industrie du pain": cte.INDUSTRY,
"Industrie du revêtement métallique sur commande": cte.INDUSTRY,
"Industrie du sucre de canne et de betterave à sucre": cte.INDUSTRY,
"Industrie du thé et du café": cte.INDUSTRY,
"Industries des appareils d'aéronefs (incluant avions et hélicoptères)": cte.INDUSTRY,
"Installation d'équipements de réfrigération commerciale": cte.WAREHOUSE,
"Installation portuaire en général": cte.WAREHOUSE,
"Jardin botanique": cte.WAREHOUSE,
"Ligne de l'oléoduc": cte.WAREHOUSE,
"Local pour les associations fraternelles": "Office",
"Logement": cte.RESIDENTIAL,
"Logement vacant dans un bâtiment comportant plusieurs logements ou autres locaux": cte.RESIDENTIAL,
"Loisir et autres activités culturelles": "Office",
"Maison d'agentsde courtiers et de services d'administration des biens-fonds": "Office",
"Maison d'étudiants (collège et université)": "Office",
"Maison de chambres et pension": "Office",
"Maison de chambres pour personnes ayant une déficience intellectuelle": "Office",
"Maison de courtiers et de négociants de marchandises": "Office",
"Maison de réhabilitation": "Office",
"Maison des jeunes": "Office",
"Maison pour personnes en difficulté (séjours périodes limitées)": "Office",
"Maison pour personnes retraitées autonomes": cte.DORMITORY,
"Maison pour personnes retraitées non autonomes (inclus les CHLSD)": cte.DORMITORY,
"Marché public": cte.STRIP_MALL,
"Meunerie et minoterie": "Office",
"Monastère": cte.DORMITORY,
"Monument et site historique": cte.EVENT_LOCATION,
"Motel": "hotel/Motel",
"Musée": cte.EVENT_LOCATION,
"Organisme international et autres organismes extraterritoriaux": "Office",
"Parc d'amusement (extérieur)": cte.NON_HEATED,
"Parc de maisons mobiles (fonds de terre seulement)": cte.NON_HEATED,
"Parc pour la récréation en général": cte.NON_HEATED,
"Parc à caractère récréatif et ornemental": cte.NON_HEATED,
"Passage": cte.NON_HEATED,
"Piscine extérieure et activités connexes": cte.NON_HEATED,
"Piscine intérieure et activités connexes": cte.SPORTS_LOCATION,
"Pose et réparation de parement métalliques et autres (entrepreneur spécialisé)": cte.WAREHOUSE,
"Poste et bureau de douanes": cte.OFFICE_AND_ADMINISTRATION,
"Pouponnière ou garderie de nuit": cte.HOSPITAL,
"Presbytère": cte.OFFICE_AND_ADMINISTRATION,
"Prison provinciale": cte.DORMITORY,
"Protection contre l'incendie et activités connexes": cte.WAREHOUSE,
"Raffinerie de pétrole": cte.INDUSTRY,
"Restaurant et établissement avec service complet (avec terrasse) - Établissements avec permis alcool inclus pub café et brasserie": cte.FULL_SERVICE_RESTAURANT,
"Restaurant et établissement avec service complet (sans terrasse) -Établissements avec permis alcoolinclus pub café et brasserie": cte.FULL_SERVICE_RESTAURANT,
"Restaurant et établissement avec service restreint ( commande au comptoir ou par téléphone)": cte.QUICK_SERVICE_RESTAURANT,
"Restaurant et établissement offrant des repas à libre-service (cafétéria cantine)": cte.QUICK_SERVICE_RESTAURANT,
"Rue et avenue pour l'accès local": cte.NON_HEATED,
"Ruelle": cte.NON_HEATED,
"Récupération et triage de matières polluantes et toxiques": cte.WAREHOUSE,
"Récupération et triage de métaux": cte.WAREHOUSE,
"Réparation et entretien des avions": cte.WAREHOUSE,
"Réserve pour la protection de la faune": cte.NON_HEATED,
"Réservoir d'eau (installation d'emmagasinage de l'eau par retenue et réservoirs)": cte.NON_HEATED,
"Résidence de tourismeappartement maison ou chalet (meublé et équipé pour repas)": "hotel/Motel",
"Salle d'exposition": cte.EVENT_LOCATION,
"Salle et terrain de squash de racquetball et de tennis": cte.SPORTS_LOCATION,
"Salle ou salon de quilles": cte.NON_HEATED,
"Salon de beauté (maquillagemanucureetc..)": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Salon de coiffure": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Salon funéraire": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Service bancaire (dépôts et prêtsincluant banque à charte)": cte.OFFICE_AND_ADMINISTRATION,
"Service d'ambulance": cte.WAREHOUSE,
"Service d'architecture": cte.OFFICE_AND_ADMINISTRATION,
"Service d'assainissement de l'environnement": cte.WAREHOUSE,
"Service d'emballage et de protection de marchandises": cte.WAREHOUSE,
"Service d'envoi de marchandises": cte.WAREHOUSE,
"Service d'hébergement des données (sites Web diffusion audio et vidéo en continu services d'application)": cte.WAREHOUSE,
"Service d'hôpital (inclus hôpitaux psychiatriques)": cte.HOSPITAL,
"Service d'optométrie": cte.OUT_PATIENT_HEALTH_CARE,
"Service de buanderie de nettoyage à sec et de teinture (sauf les tapis)": cte.WAREHOUSE,
"Service de comptabilitéde vérification et de tenue de livre": cte.OFFICE_AND_ADMINISTRATION,
"Service de construction de routesde rues et de pontsde trottoirs et de pistes (entrepreneur général)": cte.WAREHOUSE,
"Service de construction non résidentiellecommerciale et institutionnelle (entrepreneur général)": cte.WAREHOUSE,
"Service de construction non résidentielleindustrielle (entrepreneur général)": cte.WAREHOUSE,
"Service de construction résidentielle (entrepreneur)": cte.WAREHOUSE,
"Service de débosselage et de peinture d'automobiles": cte.WAREHOUSE,
"Service de garderie (prématernelle moins de 50 % de poupons)": cte.PRIMARY_SCHOOL,
"Service de génie": cte.OFFICE_AND_ADMINISTRATION,
"Service de holding et d'investissement et de fiducie": cte.OFFICE_AND_ADMINISTRATION,
"Service de laboratoire dentaire": cte.OUT_PATIENT_HEALTH_CARE,
"Service de laboratoire médical": cte.OUT_PATIENT_HEALTH_CARE,
"Service de lavage d'automobiles": cte.WAREHOUSE,
"Service de limousine": cte.WAREHOUSE,
"Service de lingerie et de buanderie industrielle": cte.WAREHOUSE,
"Service de location d'automobiles": cte.WAREHOUSE,
"Service de location d'outils ou d'équipements": cte.WAREHOUSE,
"Service de location d'équipements": cte.WAREHOUSE,
"Service de location de boites postales (sauf le publipostage) et centre de courrier privé": cte.OFFICE_AND_ADMINISTRATION,
"Service de location de camions de remorques utilitaires et de véhicules de plaisance": cte.WAREHOUSE,
"Service de maçonnerie (entrepreneur spécialisé)": cte.INDUSTRY,
"Service de messagers": "Office",
"Service de notaires": "Office",
"Service de paysagement ou de déneigement": cte.WAREHOUSE,
"Service de petite menuiserie et de finition (entrepreneur spécialisé)": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Service de plomberie de chauffagede climatisation et de ventilation (entrepreneur spécialisé)": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Service de police fédérale et activités connexes": cte.OFFICE_AND_ADMINISTRATION,
"Service de police municipale et activités connexes": cte.OFFICE_AND_ADMINISTRATION,
"Service de pose de portesde fenêtres et de panneaux de verre": cte.WAREHOUSE,
"Service de publicité en général": "Office",
"Service de recherche de développement et d'essais": cte.SECONDARY_SCHOOL,
"Service de remplacement de pièces et d'accessoires d'automobiles (amortisseurs silencieux toits ouvrants glacespare-brises...)": cte.WAREHOUSE,
"Service de revêtement en asphalte et en bitume": cte.WAREHOUSE,
"Service de réparation d'automobiles (garage) sans pompes à essence(5531)": cte.WAREHOUSE,
"Service de réparation d'autres véhicules légers": cte.WAREHOUSE,
"Service de réparation de véhicules légers motorisés (motocyclettemotoneige véhicule tout terrain)": cte.WAREHOUSE,
"Service de réparation et d'entretien de machines et de matériel d'usage commercial et industriel": "Office",
"Service de réparation et d'entretien de matériel informatique": "Office",
"Service de réparation et d'entretien de systèmes de plomberieschauffageventilation et climatisation.(entrepreneur spécialisé)": cte.WAREHOUSE,
"Service de réparation et d'entretien de véhicules lourds": cte.WAREHOUSE,
"Service de réparation et de rembourrage de meubles": cte.WAREHOUSE,
"Service de soudure": cte.WAREHOUSE,
"Service de toilettage pour animaux domestiques": cte.OUT_PATIENT_HEALTH_CARE,
"Service de traitement pour automobiles (antirouilleetc.)": cte.WAREHOUSE,
"Service de travaux d'électricité et installation de câblage (entrepreneur spécialisé)": cte.WAREHOUSE,
"Service de travaux de toiture (entrepreneur spécialisé)": cte.WAREHOUSE,
"Service de télécommunication sans fil (appareil mobile sauf par Internet)": cte.WAREHOUSE,
"Service de vétérinaires (animaux domestiques)": cte.OUT_PATIENT_HEALTH_CARE,
"Service de vétérinaires et d'hôpital pour animaux de ferme": cte.OUT_PATIENT_HEALTH_CARE,
"Service dentaire (inclus chirurgie et hygiène)": cte.OUT_PATIENT_HEALTH_CARE,
"Service en santé mentale (cabinet) (comprend tous services professionnelspsychiatre psychologuepsychanalyste)": cte.OUT_PATIENT_HEALTH_CARE,
"Service en travaux de fondation et de structures en béton (entrepreneur spécialisé)": "Office",
"Service informatique (location ou utilisation partagée services auxiliaires programmation planification et analyse de système)": "Office",
"Service médical (cabinet de médecins et chirurgiens spécialisés)": cte.OUT_PATIENT_HEALTH_CARE,
"Service photographique (incluant les services commerciaux)": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Service pour l'entretien ménager": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Service éducationnel et de recherche scientifique": cte.SECONDARY_SCHOOL,
"Services spécialisés reliés à l'activité bancaire": cte.OFFICE_AND_ADMINISTRATION,
"Stade": cte.SPORTS_LOCATION,
"Station de contrôle de la pression de l'eau": cte.WAREHOUSE,
"Station de contrôle de la pression des eaux usées": cte.WAREHOUSE,
"Station de métro": cte.WAREHOUSE,
"Station libre-serviceou avec service et dépanneur sans réparation de véhicules automobiles": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Station libre-serviceou avec service sans réparation de véhicules automobiles": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Station-service avec réparation de véhicules automobiles": cte.WAREHOUSE,
"Stationnement extérieur (condo non résidentiel)": cte.NON_HEATED,
"Stationnement extérieur (condo)": cte.NON_HEATED,
"Stationnement intérieur ( condo non résidentiel)": cte.WAREHOUSE,
"Stationnement intérieur (condo)": cte.WAREHOUSE,
"Studio d'enregistrement du son (disque cassette et disque compact)": "Office",
"Studio de production de filmsde vidéos ou de publicités (ne comprends pas le laboratoire de production)": "Office",
"Studio de télévision (sans public)": "Office",
"Syndicat et organisation similaire": "Office",
"Terminus maritime (passagers) incluant les gares de traversiers": cte.WAREHOUSE,
"Terrain de golf (avec chalet et autres aménagements sportifs)": cte.NON_HEATED,
"Terrain de sport (jeux et pistes pour compétitions et sportgradins)": cte.NON_HEATED,
"Terrain de stationnement pour automobiles": cte.WAREHOUSE,
"Terrains de stationnement pour véhicules lourds": cte.WAREHOUSE,
"Théâtre": cte.EVENT_LOCATION,
"Tour de relais (micro-ondes)": cte.NON_HEATED,
"Tous les autres services d'information": cte.NON_HEATED,
"Transport et gestion d'électricité en bloc": cte.NON_HEATED,
"Transport et gestion du gaz par canalisation": cte.NON_HEATED,
"Université": cte.SECONDARY_SCHOOL,
"Usine de traitement des eaux (filtration)": cte.INDUSTRY,
"Usine de traitement des eaux usées (épuration)": cte.INDUSTRY,
"Vente au détail (fleuriste)": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail d'accessoires pour femmes": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail d'animaux de maison (animalerie)": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail d'antiquités (sauf le marché aux puces)": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail d'appareils orthopédiques et articles spécialisés de santé": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail d'articles de sport": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail d'articles d'accessoires d'aménagement paysager et de jardin": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail d'instruments et de matériel médical": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail d'équipements de ferme": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail d'équipements de plomberie de chauffagede ventilationde climatisation et de foyer": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail d'équipements et d'accessoires de chasse et pêche": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail de bicyclettes": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail de boissons alcoolisées": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail de chaussures": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail de fruits et de légumes": cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD,
"Vente au détail de la viande": cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD,
"Vente au détail de livres et de papeterie": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail de marchandises en général (sauf les marchés aux puces)": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail de matériaux de construction": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail de matériaux de construction (cour à bois)": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail de matériel électrique": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail de meubles": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail de motocyclettes de motoneiges et de leurs accessoires": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail de médicaments et d'articles divers (pharmacie)": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail de peinturede verre et de papier tenture": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail de piscinesde spas et leurs accessoires": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail de pièces de véhicules automobiles et d'accessoires usagés": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail de pneus de batteries et d'accessoires": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail de produits d'épicerie (avec boucherie)": cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD,
"Vente au détail de produits d'épicerie (sans boucherie)": cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD,
"Vente au détail de produits de la boulangerie et de la pâtisserie (manufacturés sur place en totalité ou non)": cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD,
"Vente au détail de quincaillerie": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail de radiosde téléviseurssystèmes de son et appareils électroniques": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail de revêtements de planchers et de murs (bois franc plancher flottant carreaux céramiques tapisserie)": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail de serruresde clés et d'accessoires": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail de véhicules automobiles neufs et usagés": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail de véhicules automobiles usagés seulement": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail de vêtement prêt-à-porter pour femmes": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail de vêtements et d'accessoires pour hommes": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail de vêtements et d'articles usagésfriperies (sauf le marché aux puces)": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail de vêtements unisexes": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détail du cafédu théd'épices et d'aromates": cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD,
"Vente au détailclubs de gros et hypermarchés (entrepôt-club)": cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD,
"Vente au détailfournitures pour la maison et l'auto": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente au détailmagasin à rayons": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
"Vente en gros d'ameublements de matériels de bureau et de magasin": cte.STRIP_MALL,
"Vente en gros d'appareils et d'équipements de plomberie et de chauffage": cte.STRIP_MALL,
"Vente en gros d'appareils et d'équipements électriques de fils et de matériel électronique de construction": cte.STRIP_MALL,
"Vente en gros d'appareils électriquesde téléviseurs et de radios": cte.STRIP_MALL,
"Vente en gros d'automobiles et autres véhicules automobiles neufs ou d'occasions incluent VR)": cte.STRIP_MALL,
"Vente en gros d'autres appareils ou matériels électriques et électroniques": cte.STRIP_MALL,
"Vente en gros d'autres médicaments de produits chimiques et de produits connexes": cte.STRIP_MALL,
"Vente en gros d'autres pièces d'équipement ou de machinerie (incluant machinerie lourde)": cte.STRIP_MALL,
"Vente en gros d'autres produits reliés à l'épicerie": cte.STRIP_MALL,
"Vente en gros d'équipements et de pièces de machinerie commercialeindustrielle ou agricole (incluant machinerie lourde)": cte.STRIP_MALL,
"Vente en gros d'équipements et de pièces pour la réfrigération ventilation la climatisation et le chauffage (système combiné)": cte.STRIP_MALL,
"Vente en gros d'équipements et de pièces pour les entreprises de services": cte.STRIP_MALL,
"Vente en gros de bois et de matériaux de construction": cte.STRIP_MALL,
"Vente en gros de chaussures": cte.STRIP_MALL,
"Vente en gros de fruits et de légumes frais": cte.STRIP_MALL,
"Vente en gros de médicaments et de produits médicamenteux": cte.STRIP_MALL,
"Vente en gros de pièces et d'accessoires neufs pour véhicules automobiles": cte.STRIP_MALL,
"Vente en gros de pièces et d'équipements électroniques": cte.STRIP_MALL,
"Vente en gros de pneus et de chambres à air": cte.STRIP_MALL,
"Vente en gros de poissons et de fruits de mer": cte.STRIP_MALL,
"Vente en gros de produits de beauté": cte.STRIP_MALL,
"Vente en gros de produits de boulangerie et de pâtisserie": cte.STRIP_MALL,
"Vente en gros de produits laitiers": cte.STRIP_MALL,
"Vente en gros de quincaillerie": cte.STRIP_MALL,
"Vente en gros de tissus et de textiles": cte.STRIP_MALL,
"Vente en gros de viandes et de produits de la viande": cte.STRIP_MALL,
"Vente en gros de vêtements de lingerie de bas et d'accessoires": cte.STRIP_MALL,
"Vente en gros pour l'épicerie en général": cte.STRIP_MALL,
"École commerciale et de secrétariat (non intégrée aux polyvalentes)": cte.SECONDARY_SCHOOL,
"École de beaux-arts et de musique (exclus arts publicitaires arts graphiques et photographie publicitaire)": cte.SECONDARY_SCHOOL,
"École de danse": cte.SECONDARY_SCHOOL,
"École de métiers (non intégrée aux polyvalentes)": cte.SECONDARY_SCHOOL,
"École maternelle": cte.SECONDARY_SCHOOL,
"École polyvalente": cte.SECONDARY_SCHOOL,
"École secondaire": cte.SECONDARY_SCHOOL,
"École à caractère familial (exploité par une personne physique dans sa résidence moins de 15 élèves)": cte.SECONDARY_SCHOOL,
"École élémentaire": cte.SECONDARY_SCHOOL,
"École élémentaire et secondaire": cte.SECONDARY_SCHOOL,
"Église synagogue mosquée et temple": cte.EVENT_LOCATION,
"Établissement avec salle de réception ou de banquet": cte.FULL_SERVICE_RESTAURANT,
"Établissement avec service de boissons alcoolisées (Bar)": cte.QUICK_SERVICE_RESTAURANT,
"Établissement dont l'activité principale est la danse (discothèque avec service alcool boite de nuit) sans alcool code 7397": cte.QUICK_SERVICE_RESTAURANT,
"Mausolée": cte.NON_HEATED,
"Auberge ou gîte touristique (Hôtel à caractère familial, d'au plus 3 étages en hauteur de bâtiment)": cte.HOTEL,
"Service de garderie (prématernelle, moins de 50 % de poupons)": cte.PRIMARY_SCHOOL,
"Église, synagogue, mosquée et temple": cte.CONVENTION_CENTER
}
@property
def dictionary(self) -> dict:
return self._dictionary

View File

@ -0,0 +1,217 @@
"""
Dictionaries module for Pluto function to hub function
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
"""
import hub.helpers.constants as cte
class PlutoFunctionToHubFunction:
def __init__(self):
self._dictionary = {
'A0': cte.SINGLE_FAMILY_HOUSE,
'A1': cte.SINGLE_FAMILY_HOUSE,
'A2': cte.SINGLE_FAMILY_HOUSE,
'A3': cte.SINGLE_FAMILY_HOUSE,
'A4': cte.SINGLE_FAMILY_HOUSE,
'A5': cte.SINGLE_FAMILY_HOUSE,
'A6': cte.SINGLE_FAMILY_HOUSE,
'A7': cte.SINGLE_FAMILY_HOUSE,
'A8': cte.SINGLE_FAMILY_HOUSE,
'A9': cte.SINGLE_FAMILY_HOUSE,
'B1': cte.MULTI_FAMILY_HOUSE,
'B2': cte.MULTI_FAMILY_HOUSE,
'B3': cte.MULTI_FAMILY_HOUSE,
'B9': cte.MULTI_FAMILY_HOUSE,
'C0': cte.RESIDENTIAL,
'C1': cte.RESIDENTIAL,
'C2': cte.RESIDENTIAL,
'C3': cte.RESIDENTIAL,
'C4': cte.RESIDENTIAL,
'C5': cte.RESIDENTIAL,
'C6': cte.RESIDENTIAL,
'C7': cte.RESIDENTIAL,
'C8': cte.RESIDENTIAL,
'C9': cte.RESIDENTIAL,
'D0': cte.RESIDENTIAL,
'D1': cte.RESIDENTIAL,
'D2': cte.RESIDENTIAL,
'D3': cte.RESIDENTIAL,
'D4': cte.RESIDENTIAL,
'D5': cte.RESIDENTIAL,
'D6': cte.RESIDENTIAL,
'D7': cte.RESIDENTIAL,
'D8': cte.RESIDENTIAL,
'D9': cte.RESIDENTIAL,
'E1': cte.WAREHOUSE,
'E3': cte.WAREHOUSE,
'E4': cte.WAREHOUSE,
'E5': cte.WAREHOUSE,
'E7': cte.WAREHOUSE,
'E9': cte.WAREHOUSE,
'F1': cte.WAREHOUSE,
'F2': cte.WAREHOUSE,
'F4': cte.WAREHOUSE,
'F5': cte.WAREHOUSE,
'F8': cte.WAREHOUSE,
'F9': cte.WAREHOUSE,
'G0': cte.SMALL_OFFICE,
'G1': cte.SMALL_OFFICE,
'G2': cte.SMALL_OFFICE,
'G3': cte.SMALL_OFFICE,
'G4': cte.SMALL_OFFICE,
'G5': cte.SMALL_OFFICE,
'G6': cte.SMALL_OFFICE,
'G7': cte.SMALL_OFFICE,
'G8': cte.SMALL_OFFICE,
'G9': cte.SMALL_OFFICE,
'H1': cte.HOTEL,
'H2': cte.HOTEL,
'H3': cte.HOTEL,
'H4': cte.HOTEL,
'H5': cte.HOTEL,
'H6': cte.HOTEL,
'H7': cte.HOTEL,
'H8': cte.HOTEL,
'H9': cte.HOTEL,
'HB': cte.HOTEL,
'HH': cte.HOTEL,
'HR': cte.HOTEL,
'HS': cte.HOTEL,
'I1': cte.HOSPITAL,
'I2': cte.OUT_PATIENT_HEALTH_CARE,
'I3': cte.OUT_PATIENT_HEALTH_CARE,
'I4': cte.RESIDENTIAL,
'I5': cte.OUT_PATIENT_HEALTH_CARE,
'I6': cte.OUT_PATIENT_HEALTH_CARE,
'I7': cte.OUT_PATIENT_HEALTH_CARE,
'I9': cte.OUT_PATIENT_HEALTH_CARE,
'J1': cte.LARGE_OFFICE,
'J2': cte.LARGE_OFFICE,
'J3': cte.LARGE_OFFICE,
'J4': cte.LARGE_OFFICE,
'J5': cte.LARGE_OFFICE,
'J6': cte.LARGE_OFFICE,
'J7': cte.LARGE_OFFICE,
'J8': cte.LARGE_OFFICE,
'J9': cte.LARGE_OFFICE,
'K1': cte.STRIP_MALL,
'K2': cte.STRIP_MALL,
'K3': cte.STRIP_MALL,
'K4': cte.RESIDENTIAL,
'K5': cte.RESTAURANT,
'K6': cte.SUPERMARKET,
'K7': cte.SUPERMARKET,
'K8': cte.SUPERMARKET,
'K9': cte.SUPERMARKET,
'L1': cte.RESIDENTIAL,
'L2': cte.RESIDENTIAL,
'L3': cte.RESIDENTIAL,
'L8': cte.RESIDENTIAL,
'L9': cte.RESIDENTIAL,
'M1': cte.LARGE_OFFICE,
'M2': cte.LARGE_OFFICE,
'M3': cte.LARGE_OFFICE,
'M4': cte.LARGE_OFFICE,
'M9': cte.LARGE_OFFICE,
'N1': cte.RESIDENTIAL,
'N2': cte.RESIDENTIAL,
'N3': cte.RESIDENTIAL,
'N4': cte.RESIDENTIAL,
'N9': cte.RESIDENTIAL,
'O1': cte.SMALL_OFFICE,
'O2': cte.SMALL_OFFICE,
'O3': cte.SMALL_OFFICE,
'O4': cte.SMALL_OFFICE,
'O5': cte.SMALL_OFFICE,
'O6': cte.SMALL_OFFICE,
'O7': cte.SMALL_OFFICE,
'O8': cte.SMALL_OFFICE,
'O9': cte.SMALL_OFFICE,
'P1': cte.LARGE_OFFICE,
'P2': cte.HOTEL,
'P3': cte.SMALL_OFFICE,
'P4': cte.SMALL_OFFICE,
'P5': cte.SMALL_OFFICE,
'P6': cte.SMALL_OFFICE,
'P7': cte.LARGE_OFFICE,
'P8': cte.LARGE_OFFICE,
'P9': cte.SMALL_OFFICE,
'Q0': cte.SMALL_OFFICE,
'Q1': cte.SMALL_OFFICE,
'Q2': cte.SMALL_OFFICE,
'Q3': cte.SMALL_OFFICE,
'Q4': cte.SMALL_OFFICE,
'Q5': cte.SMALL_OFFICE,
'Q6': cte.SMALL_OFFICE,
'Q7': cte.SMALL_OFFICE,
'Q8': cte.SMALL_OFFICE,
'Q9': cte.SMALL_OFFICE,
'R0': cte.RESIDENTIAL,
'R1': cte.RESIDENTIAL,
'R2': cte.RESIDENTIAL,
'R3': cte.RESIDENTIAL,
'R4': cte.RESIDENTIAL,
'R5': cte.RESIDENTIAL,
'R6': cte.RESIDENTIAL,
'R7': cte.RESIDENTIAL,
'R8': cte.RESIDENTIAL,
'R9': cte.RESIDENTIAL,
'RA': cte.RESIDENTIAL,
'RB': cte.RESIDENTIAL,
'RC': cte.RESIDENTIAL,
'RD': cte.RESIDENTIAL,
'RG': cte.RESIDENTIAL,
'RH': cte.RESIDENTIAL,
'RI': cte.RESIDENTIAL,
'RK': cte.RESIDENTIAL,
'RM': cte.RESIDENTIAL,
'RR': cte.RESIDENTIAL,
'RS': cte.RESIDENTIAL,
'RW': cte.RESIDENTIAL,
'RX': cte.RESIDENTIAL,
'RZ': cte.RESIDENTIAL,
'S0': cte.RESIDENTIAL,
'S1': cte.RESIDENTIAL,
'S2': cte.RESIDENTIAL,
'S3': cte.RESIDENTIAL,
'S4': cte.RESIDENTIAL,
'S5': cte.RESIDENTIAL,
'S9': cte.RESIDENTIAL,
'U0': cte.WAREHOUSE,
'U1': cte.WAREHOUSE,
'U2': cte.WAREHOUSE,
'U3': cte.WAREHOUSE,
'U4': cte.WAREHOUSE,
'U5': cte.WAREHOUSE,
'U6': cte.WAREHOUSE,
'U7': cte.WAREHOUSE,
'U8': cte.WAREHOUSE,
'U9': cte.WAREHOUSE,
'W1': cte.PRIMARY_SCHOOL,
'W2': cte.PRIMARY_SCHOOL,
'W3': cte.SECONDARY_SCHOOL,
'W4': cte.EDUCATION,
'W5': cte.SECONDARY_SCHOOL,
'W6': cte.SECONDARY_SCHOOL,
'W7': cte.SECONDARY_SCHOOL,
'W8': cte.PRIMARY_SCHOOL,
'W9': cte.SECONDARY_SCHOOL,
'Y1': cte.LARGE_OFFICE,
'Y2': cte.LARGE_OFFICE,
'Y3': cte.LARGE_OFFICE,
'Y4': cte.LARGE_OFFICE,
'Y5': cte.LARGE_OFFICE,
'Y6': cte.LARGE_OFFICE,
'Y7': cte.LARGE_OFFICE,
'Y8': cte.LARGE_OFFICE,
'Y9': cte.LARGE_OFFICE,
'Z1': cte.LARGE_OFFICE
}
@property
def dictionary(self) -> dict:
return self._dictionary

View File

@ -0,0 +1,92 @@
"""
Dictionaries module saves all transformations of functions and usages to access the catalogs
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from hub.helpers.data.hft_function_to_hub_function import HftFunctionToHubFunction
from hub.helpers.data.montreal_function_to_hub_function import MontrealFunctionToHubFunction
from hub.helpers.data.alkis_function_to_hub_function import AlkisFunctionToHubFunction
from hub.helpers.data.pluto_function_to_hub_function import PlutoFunctionToHubFunction
from hub.helpers.data.hub_function_to_nrel_construction_function import HubFunctionToNrelConstructionFunction
from hub.helpers.data.hub_function_to_nrcan_construction_function import HubFunctionToNrcanConstructionFunction
from hub.helpers.data.hub_usage_to_comnet_usage import HubUsageToComnetUsage
from hub.helpers.data.hub_usage_to_hft_usage import HubUsageToHftUsage
from hub.helpers.data.hub_usage_to_nrcan_usage import HubUsageToNrcanUsage
class Dictionaries:
"""
Dictionaries class
"""
@property
def hub_usage_to_hft_usage(self) -> dict:
"""
Hub usage to HfT usage, transformation dictionary
:return: dict
"""
return HubUsageToHftUsage().dictionary
@property
def hub_usage_to_comnet_usage(self) -> dict:
"""
Hub usage to Comnet usage, transformation dictionary
:return: dict
"""
return HubUsageToComnetUsage().dictionary
@property
def hub_usage_to_nrcan_usage(self) -> dict:
"""
Get hub usage to NRCAN usage, transformation dictionary
:return: dict
"""
return HubUsageToNrcanUsage().dictionary
@property
def hub_function_to_nrcan_construction_function(self) -> dict:
"""
Get hub function to NRCAN construction function, transformation dictionary
:return: dict
"""
return HubFunctionToNrcanConstructionFunction().dictionary
@property
def hub_function_to_nrel_construction_function(self) -> dict:
"""
Get hub function to NREL construction function, transformation dictionary
:return: dict
"""
return HubFunctionToNrelConstructionFunction().dictionary
@property
def pluto_function_to_hub_function(self) -> dict:
"""
Get Pluto function to hub function, transformation dictionary
:return: dict
"""
return PlutoFunctionToHubFunction().dictionary
@property
def hft_function_to_hub_function(self) -> dict:
"""
Get Hft function to hub function, transformation dictionary
:return: dict
"""
return HftFunctionToHubFunction().dictionary
@property
def montreal_function_to_hub_function(self) -> dict:
"""
Get Montreal function to hub function, transformation dictionary
"""
return MontrealFunctionToHubFunction().dictionary
@property
def alkis_function_to_hub_function(self) -> dict:
"""
Get Alkis function to hub function, transformation dictionary
"""
return AlkisFunctionToHubFunction().dictionary

View File

@ -39,59 +39,12 @@ class GeometryHelper:
max_distance = ConfigurationHelper().max_location_distance_for_shared_walls max_distance = ConfigurationHelper().max_location_distance_for_shared_walls
return GeometryHelper.distance_between_points(location1, location2) < max_distance return GeometryHelper.distance_between_points(location1, location2) < max_distance
def almost_same_area(self, area_1, area_2):
"""
Compare two areas and decides if they are almost equal (absolute error under delta)
:param area_1
:param area_2
:return: Boolean
"""
if area_1 == 0 or area_2 == 0:
return False
delta = math.fabs(area_1 - area_2)
return delta <= self._area_delta
def is_almost_same_surface(self, surface_1, surface_2):
"""
Compare two surfaces and decides if they are almost equal (quadratic error under delta)
:param surface_1: Surface
:param surface_2: Surface
:return: Boolean
"""
# delta is grads an need to be converted into radians
delta = np.rad2deg(self._delta)
difference = (surface_1.inclination - surface_2.inclination) % math.pi
if abs(difference) > delta:
return False
# s1 and s2 are at least almost parallel surfaces
# calculate distance point to plane using all the vertex
# select surface1 value for the point (X,Y,Z) where two of the values are 0
minimum_distance = self._delta + 1
parametric = surface_2.polygon.get_parametric()
normal_2 = surface_2.normal
for point in surface_1.points:
distance = abs(
(point[0] * parametric[0]) + (point[1] * parametric[1]) + (point[2] * parametric[2]) + parametric[3])
normal_module = math.sqrt(pow(normal_2[0], 2) + pow(normal_2[1], 2) + pow(normal_2[2], 2))
if normal_module == 0:
continue
distance = distance / normal_module
if distance < minimum_distance:
minimum_distance = distance
if minimum_distance <= self._delta:
break
if minimum_distance > self._delta or surface_1.intersect(surface_2) is None:
return False
return True
@staticmethod @staticmethod
def segment_list_to_trimesh(lines) -> Trimesh: def segment_list_to_trimesh(lines) -> Trimesh:
""" """
Transform a list of segments into a Trimesh Transform a list of segments into a Trimesh
""" """
# todo: trimesh has a method for this
line_points = [lines[0][0], lines[0][1]] line_points = [lines[0][0], lines[0][1]]
lines.remove(lines[0]) lines.remove(lines[0])
while len(lines) > 1: while len(lines) > 1:
@ -106,7 +59,7 @@ class GeometryHelper:
line_points.append(line[0]) line_points.append(line[0])
lines.pop(i - 1) lines.pop(i - 1)
break break
polyhedron = Polyhedron(Polygon(line_points).triangulate()) polyhedron = Polyhedron(Polygon(line_points).triangles)
trimesh = Trimesh(polyhedron.vertices, polyhedron.faces) trimesh = Trimesh(polyhedron.vertices, polyhedron.faces)
return trimesh return trimesh

View File

@ -1,138 +0,0 @@
"""
monthly_to_hourly_demand module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import calendar as cal
import pandas as pd
from hub.city_model_structure.building_demand.occupant import Occupant
import hub.helpers.constants as cte
class MonthlyToHourlyDemand:
"""
MonthlyToHourlyDemand class
"""
def __init__(self, building, conditioning_seasons):
self._hourly_heating = pd.DataFrame()
self._hourly_cooling = pd.DataFrame()
self._building = building
self._conditioning_seasons = conditioning_seasons
def hourly_heating(self, key):
"""
hourly distribution of the monthly heating of a building
:param key: string
:return: [hourly_heating]
"""
# todo: this method and the insel model have to be reviewed for more than one thermal zone
external_temp = self._building.external_temperature[cte.HOUR]
# todo: review index depending on how the schedules are defined, either 8760 or 24 hours
for usage_zone in self._building.usage_zones:
temp_set = float(usage_zone.heating_setpoint)-3
temp_back = float(usage_zone.heating_setback)-3
# todo: if these are data frames, then they should be called as (Occupancy should be in low case):
# usage_zone.schedules.Occupancy
# self._conditioning_seasons.heating
occupancy = Occupant().get_complete_year_schedule(usage_zone.schedules['Occupancy'])
heating_schedule = self._conditioning_seasons['heating']
hourly_heating = []
i = 0
j = 0
temp_grad_day = []
for month in range(1, 13):
temp_grad_month = 0
month_range = cal.monthrange(2015, month)[1]
for _ in range(1, month_range+1):
external_temp_med = 0
for hour in range(0, 24):
external_temp_med += external_temp[key][i]/24
for hour in range(0, 24):
if external_temp_med < temp_set and heating_schedule[month-1] == 1:
if occupancy[hour] > 0:
hdd = temp_set - external_temp[key][i]
if hdd < 0:
hdd = 0
temp_grad_day.append(hdd)
else:
hdd = temp_back - external_temp[key][i]
if hdd < 0:
hdd = 0
temp_grad_day.append(hdd)
else:
temp_grad_day.append(0)
temp_grad_month += temp_grad_day[i]
i += 1
for _ in range(1, month_range + 1):
for hour in range(0, 24):
monthly_demand = self._building.heating[cte.MONTH][month-1]
if monthly_demand == 'NaN':
monthly_demand = 0
if temp_grad_month == 0:
hourly_demand = 0
else:
hourly_demand = float(monthly_demand)*float(temp_grad_day[j])/float(temp_grad_month)
hourly_heating.append(hourly_demand)
j += 1
self._hourly_heating = pd.DataFrame(data=hourly_heating, columns=['monthly to hourly'])
return self._hourly_heating
def hourly_cooling(self, key):
"""
hourly distribution of the monthly cooling of a building
:param key: string
:return: [hourly_cooling]
"""
# todo: this method and the insel model have to be reviewed for more than one thermal zone
external_temp = self._building.external_temperature[cte.HOUR]
# todo: review index depending on how the schedules are defined, either 8760 or 24 hours
for usage_zone in self._building.usage_zones:
temp_set = float(usage_zone.cooling_setpoint)
temp_back = 100
occupancy = Occupant().get_complete_year_schedule(usage_zone.schedules['Occupancy'])
cooling_schedule = self._conditioning_seasons['cooling']
hourly_cooling = []
i = 0
j = 0
temp_grad_day = []
for month in range(1, 13):
temp_grad_month = 0
month_range = cal.monthrange(2015, month)[1]
for _ in range(1, month_range[1] + 1):
for hour in range(0, 24):
if external_temp[key][i] > temp_set and cooling_schedule[month - 1] == 1:
if occupancy[hour] > 0:
cdd = external_temp[key][i] - temp_set
if cdd < 0:
cdd = 0
temp_grad_day.append(cdd)
else:
cdd = external_temp[key][i] - temp_back
if cdd < 0:
cdd = 0
temp_grad_day.append(cdd)
else:
temp_grad_day.append(0)
temp_grad_month += temp_grad_day[i]
i += 1
for _ in range(1, month_range[1] + 1):
for hour in range(0, 24):
# monthly_demand = self._building.heating[cte.MONTH]['INSEL'][month-1]
monthly_demand = self._building.cooling[cte.MONTH][month - 1]
if monthly_demand == 'NaN':
monthly_demand = 0
if temp_grad_month == 0:
hourly_demand = 0
else:
hourly_demand = float(monthly_demand) * float(temp_grad_day[j]) / float(temp_grad_month)
hourly_cooling.append(hourly_demand)
j += 1
self._hourly_cooling = pd.DataFrame(data=hourly_cooling, columns=['monthly to hourly'])
return self._hourly_cooling

18
hub/helpers/utils.py Normal file
View File

@ -0,0 +1,18 @@
"""
Constant module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Peter Yefi peteryefi@gmail.com
"""
def validate_import_export_type(cls_name: type):
"""
Retrieves all the function names in a class which are property types (decoration)
and normal functions
:param cls_name: the class name
:return: [str], a list of functions in the class
"""
return [func for func in dir(cls_name)
if (type(getattr(cls_name, func)) is property or callable(getattr(cls_name, func)))
and func in cls_name.__dict__ and func[0] == '_' and func != '__init__']

View File

@ -1,98 +0,0 @@
"""
BuildingArchetype stores construction information by building archetypes
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from typing import List
from hub.imports.construction.data_classes.thermal_boundary_archetype import ThermalBoundaryArchetype
class BuildingArchetype:
"""
BuildingArchetype class
"""
def __init__(self, archetype_keys, average_storey_height, storeys_above_ground, effective_thermal_capacity,
additional_thermal_bridge_u_value, indirectly_heated_area_ratio, infiltration_rate_system_off,
infiltration_rate_system_on, thermal_boundary_archetypes):
self._archetype_keys = archetype_keys
self._average_storey_height = average_storey_height
self._storeys_above_ground = storeys_above_ground
self._effective_thermal_capacity = effective_thermal_capacity
self._additional_thermal_bridge_u_value = additional_thermal_bridge_u_value
self._indirectly_heated_area_ratio = indirectly_heated_area_ratio
self._infiltration_rate_system_off = infiltration_rate_system_off
self._infiltration_rate_system_on = infiltration_rate_system_on
self._thermal_boundary_archetypes = thermal_boundary_archetypes
@property
def archetype_keys(self) -> {}:
"""
Get keys that define the archetype
:return: dictionary
"""
return self._archetype_keys
@property
def average_storey_height(self):
"""
Get archetype's building storey height in meters
:return: float
"""
return self._average_storey_height
@property
def storeys_above_ground(self):
"""
Get archetype's building storey height in meters
:return: float
"""
return self._storeys_above_ground
@property
def effective_thermal_capacity(self):
"""
Get archetype's effective thermal capacity in J/m2K
:return: float
"""
return self._effective_thermal_capacity
@property
def additional_thermal_bridge_u_value(self):
"""
Get archetype's additional U value due to thermal bridges per area of shell in W/m2K
:return: float
"""
return self._additional_thermal_bridge_u_value
@property
def indirectly_heated_area_ratio(self):
"""
Get archetype's indirectly heated area ratio
:return: float
"""
return self._indirectly_heated_area_ratio
@property
def infiltration_rate_system_off(self):
"""
Get archetype's infiltration rate when conditioning systems OFF in air changes per hour (ACH)
:return: float
"""
return self._infiltration_rate_system_off
@property
def infiltration_rate_system_on(self):
"""
Get archetype's infiltration rate when conditioning systems ON in air changes per hour (ACH)
:return: float
"""
return self._infiltration_rate_system_on
@property
def thermal_boundary_archetypes(self) -> List[ThermalBoundaryArchetype]:
"""
Get thermal boundary archetypes associated to the building archetype
:return: list of boundary archetypes
"""
return self._thermal_boundary_archetypes

View File

@ -1,104 +0,0 @@
"""
LayerArchetype stores layer and materials information, complementing the BuildingArchetype class
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
class LayerArchetype:
"""
LayerArchetype class
"""
def __init__(self, name, solar_absorptance, thermal_absorptance, visible_absorptance, thickness=None,
conductivity=None, specific_heat=None, density=None, no_mass=False, thermal_resistance=None):
self._thickness = thickness
self._conductivity = conductivity
self._specific_heat = specific_heat
self._density = density
self._solar_absorptance = solar_absorptance
self._thermal_absorptance = thermal_absorptance
self._visible_absorptance = visible_absorptance
self._no_mass = no_mass
self._name = name
self._thermal_resistance = thermal_resistance
@property
def thickness(self):
"""
Get thickness in meters
:return: float
"""
return self._thickness
@property
def conductivity(self):
"""
Get conductivity in W/mK
:return: float
"""
return self._conductivity
@property
def specific_heat(self):
"""
Get specific heat in J/kgK
:return: float
"""
return self._specific_heat
@property
def density(self):
"""
Get density in kg/m3
:return: float
"""
return self._density
@property
def solar_absorptance(self):
"""
Get solar absorptance
:return: float
"""
return self._solar_absorptance
@property
def thermal_absorptance(self):
"""
Get thermal absorptance
:return: float
"""
return self._thermal_absorptance
@property
def visible_absorptance(self):
"""
Get visible absorptance
:return: float
"""
return self._visible_absorptance
@property
def no_mass(self) -> bool:
"""
Get no mass flag
:return: Boolean
"""
return self._no_mass
@property
def name(self):
"""
Get name
:return: str
"""
return self._name
@property
def thermal_resistance(self):
"""
Get thermal resistance in m2K/W
:return: float
"""
return self._thermal_resistance

View File

@ -1,137 +0,0 @@
"""
ThermalBoundaryArchetype stores thermal boundaries information, complementing the BuildingArchetype class
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from typing import List
from hub.imports.construction.data_classes.layer_archetype import LayerArchetype
from hub.imports.construction.data_classes.thermal_opening_archetype import ThermalOpeningArchetype
class ThermalBoundaryArchetype:
"""
ThermalBoundaryArchetype class
"""
def __init__(self, boundary_type, window_ratio, construction_name, layers, thermal_opening,
outside_solar_absorptance=None, outside_thermal_absorptance=None, outside_visible_absorptance=None,
overall_u_value=None, shortwave_reflectance=None, inside_emissivity=None, alpha_coefficient=None,
radiative_coefficient=None):
self._boundary_type = boundary_type
self._outside_solar_absorptance = outside_solar_absorptance
self._outside_thermal_absorptance = outside_thermal_absorptance
self._outside_visible_absorptance = outside_visible_absorptance
self._window_ratio = window_ratio
self._construction_name = construction_name
self._overall_u_value = overall_u_value
self._layers = layers
self._thermal_opening_archetype = thermal_opening
self._shortwave_reflectance = shortwave_reflectance
self._inside_emissivity = inside_emissivity
self._alpha_coefficient = alpha_coefficient
self._radiative_coefficient = radiative_coefficient
@property
def boundary_type(self):
"""
Get type
:return: str
"""
return self._boundary_type
@property
def outside_solar_absorptance(self):
"""
Get outside solar absorptance
:return: float
"""
return self._outside_solar_absorptance
@property
def outside_thermal_absorptance(self):
"""
Get outside thermal absorptance
:return: float
"""
return self._outside_thermal_absorptance
@property
def outside_visible_absorptance(self):
"""
Get outside visible absorptance
:return: float
"""
return self._outside_visible_absorptance
@property
def window_ratio(self):
"""
Get window ratio
:return: float
"""
return self._window_ratio
@property
def construction_name(self):
"""
Get construction name
:return: str
"""
return self._construction_name
@property
def layers(self) -> List[LayerArchetype]:
"""
Get layers
:return: [NrelLayerArchetype]
"""
return self._layers
@property
def thermal_opening_archetype(self) -> ThermalOpeningArchetype:
"""
Get thermal opening archetype
:return: ThermalOpeningArchetype
"""
return self._thermal_opening_archetype
@property
def overall_u_value(self):
"""
Get overall U-value in W/m2K
:return: float
"""
return self._overall_u_value
@property
def shortwave_reflectance(self):
"""
Get shortwave reflectance
:return: float
"""
return self._shortwave_reflectance
@property
def inside_emissivity(self):
"""
Get emissivity inside
:return: float
"""
return self._inside_emissivity
@property
def alpha_coefficient(self):
"""
Get alpha coefficient
:return: float
"""
return self._alpha_coefficient
@property
def radiative_coefficient(self):
"""
Get radiative coefficient
:return: float
"""
return self._radiative_coefficient

View File

@ -1,131 +0,0 @@
"""
ThermalOpeningArchetype stores thermal openings information, complementing the BuildingArchetype class
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
class ThermalOpeningArchetype:
"""
ThermalOpeningArchetype class
"""
def __init__(self, conductivity=None, frame_ratio=None, g_value=None, thickness=None,
back_side_solar_transmittance_at_normal_incidence=None,
front_side_solar_transmittance_at_normal_incidence=None, overall_u_value=None,
openable_ratio=None, inside_emissivity=None, alpha_coefficient=None, radiative_coefficient=None,
construction_name=None):
self._conductivity = conductivity
self._frame_ratio = frame_ratio
self._g_value = g_value
self._thickness = thickness
self._back_side_solar_transmittance_at_normal_incidence = back_side_solar_transmittance_at_normal_incidence
self._front_side_solar_transmittance_at_normal_incidence = front_side_solar_transmittance_at_normal_incidence
self._overall_u_value = overall_u_value
self._openable_ratio = openable_ratio
self._inside_emissivity = inside_emissivity
self._alpha_coefficient = alpha_coefficient
self._radiative_coefficient = radiative_coefficient
self._construction_name = construction_name
@property
def conductivity(self):
"""
Get conductivity in W/mK
:return: float
"""
return self._conductivity
@property
def frame_ratio(self):
"""
Get frame ratio
:return: float
"""
return self._frame_ratio
@property
def g_value(self):
"""
Get g-value, also called shgc
:return: float
"""
return self._g_value
@property
def thickness(self):
"""
Get thickness in meters
:return: float
"""
return self._thickness
@property
def back_side_solar_transmittance_at_normal_incidence(self):
"""
Get back side solar transmittance at normal incidence
:return: float
"""
return self._back_side_solar_transmittance_at_normal_incidence
@property
def front_side_solar_transmittance_at_normal_incidence(self):
"""
Get front side solar transmittance at normal incidence
:return: float
"""
return self._front_side_solar_transmittance_at_normal_incidence
@property
def overall_u_value(self):
"""
Get overall U-value in W/m2K
:return: float
"""
return self._overall_u_value
@property
def openable_ratio(self):
"""
Get openable ratio
:return: float
"""
return self._openable_ratio
@property
def inside_emissivity(self):
"""
Get emissivity inside
:return: float
"""
return self._inside_emissivity
@property
def alpha_coefficient(self):
"""
Get alpha coefficient
:return: float
"""
return self._alpha_coefficient
@property
def radiative_coefficient(self):
"""
Get radiative coefficient
:return: float
"""
return self._radiative_coefficient
@property
def construction_name(self):
"""
Get thermal opening construction name
"""
return self._construction_name
@construction_name.setter
def construction_name(self, value):
"""
Set thermal opening construction name
"""
self._construction_name = value

View File

@ -4,7 +4,7 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
import sys
from hub.helpers import constants as cte from hub.helpers import constants as cte
@ -13,30 +13,6 @@ class ConstructionHelper:
Construction helper Construction helper
""" """
# NREL # NREL
_function_to_nrel = {
cte.RESIDENTIAL: 'residential',
cte.SINGLE_FAMILY_HOUSE: 'residential',
cte.MULTI_FAMILY_HOUSE: 'residential',
cte.ROW_HOSE: 'residential',
cte.MID_RISE_APARTMENT: 'midrise apartment',
cte.HIGH_RISE_APARTMENT: 'high-rise apartment',
cte.SMALL_OFFICE: 'small office',
cte.MEDIUM_OFFICE: 'medium office',
cte.LARGE_OFFICE: 'large office',
cte.PRIMARY_SCHOOL: 'primary school',
cte.SECONDARY_SCHOOL: 'secondary school',
cte.STAND_ALONE_RETAIL: 'stand-alone retail',
cte.HOSPITAL: 'hospital',
cte.OUT_PATIENT_HEALTH_CARE: 'outpatient healthcare',
cte.STRIP_MALL: 'strip mall',
cte.SUPERMARKET: 'supermarket',
cte.WAREHOUSE: 'warehouse',
cte.QUICK_SERVICE_RESTAURANT: 'quick service restaurant',
cte.FULL_SERVICE_RESTAURANT: 'full service restaurant',
cte.SMALL_HOTEL: 'small hotel',
cte.LARGE_HOTEL: 'large hotel'
}
_nrel_standards = { _nrel_standards = {
'ASHRAE Std189': 1, 'ASHRAE Std189': 1,
'ASHRAE 90.1_2004': 2 'ASHRAE 90.1_2004': 2
@ -71,18 +47,6 @@ class ConstructionHelper:
cte.ROOF: 'roof' cte.ROOF: 'roof'
} }
@staticmethod
def nrel_from_libs_function(function):
"""
Get NREL function from the given internal function key
:param function: str
:return: str
"""
try:
return ConstructionHelper._function_to_nrel[function]
except KeyError:
sys.stderr.write('Error: keyword not found.\n')
@staticmethod @staticmethod
def yoc_to_nrel_standard(year_of_construction): def yoc_to_nrel_standard(year_of_construction):
""" """

View File

@ -49,7 +49,7 @@ class StoreysGeneration:
thermal_zones = [storey.thermal_zone] thermal_zones = [storey.thermal_zone]
else: else:
# internal thermal boundary -> two thermal zones # internal thermal boundary -> two thermal zones
grad = np.rad2deg(thermal_boundary.inclination) grad = np.rad2deg(thermal_boundary.parent_surface.inclination)
if grad >= 170: if grad >= 170:
thermal_zones = [storey.thermal_zone, storey.neighbours[0]] thermal_zones = [storey.thermal_zone, storey.neighbours[0]]
else: else:
@ -116,7 +116,7 @@ class StoreysGeneration:
thermal_zones = [storey.thermal_zone] thermal_zones = [storey.thermal_zone]
else: else:
# internal thermal boundary -> two thermal zones # internal thermal boundary -> two thermal zones
grad = np.rad2deg(thermal_boundary.inclination) grad = np.rad2deg(thermal_boundary.parent_surface.inclination)
if grad >= 170: if grad >= 170:
thermal_zones = [storey.thermal_zone, storey.neighbours[0]] thermal_zones = [storey.thermal_zone, storey.neighbours[0]]
else: else:

View File

@ -0,0 +1,189 @@
"""
NrcanPhysicsParameters import the construction and material information defined by NRCAN
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import sys
from hub.catalog_factories.construction_catalog_factory import ConstructionCatalogFactory
from hub.city_model_structure.building_demand.layer import Layer
from hub.city_model_structure.building_demand.material import Material
from hub.helpers.dictionaries import Dictionaries
from hub.imports.construction.helpers.construction_helper import ConstructionHelper
from hub.imports.construction.helpers.storeys_generation import StoreysGeneration
class NrcanPhysicsParameters:
"""
NrcanPhysicsParameters class
"""
def __init__(self, city, base_path, divide_in_storeys=False):
self._city = city
self._path = base_path
self._divide_in_storeys = divide_in_storeys
self._climate_zone = ConstructionHelper.city_to_nrel_climate_zone(city.name)
def enrich_buildings(self):
"""
Returns the city with the construction parameters assigned to the buildings
"""
city = self._city
canel_catalog = ConstructionCatalogFactory('nrcan').catalog
for building in city.buildings:
try:
function = Dictionaries().hub_function_to_nrcan_construction_function[building.function]
archetype = self._search_archetype(canel_catalog, function, building.year_of_construction,
self._climate_zone)
except KeyError:
sys.stderr.write(f'Building {building.name} has unknown construction archetype for building function: '
f'{building.function} and building year of construction: {building.year_of_construction} '
f'and climate zone reference norm {self._climate_zone}\n')
return
# if building has no thermal zones defined from geometry, and the building will be divided in storeys,
# one thermal zone per storey is assigned
if len(building.internal_zones) == 1:
if building.internal_zones[0].thermal_zones is None:
self._create_storeys(building, archetype, self._divide_in_storeys)
if self._divide_in_storeys:
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones:
thermal_zone.total_floor_area = thermal_zone.footprint_area
else:
number_of_storeys = int(float(building.eave_height) / float(building.average_storey_height))
thermal_zone = building.internal_zones[0].thermal_zones[0]
thermal_zone.total_floor_area = thermal_zone.footprint_area * number_of_storeys
else:
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones:
thermal_zone.total_floor_area = thermal_zone.footprint_area
for internal_zone in building.internal_zones:
self._assign_values(internal_zone.thermal_zones, archetype)
for thermal_zone in internal_zone.thermal_zones:
self._calculate_view_factors(thermal_zone)
@staticmethod
def _search_archetype(nrel_catalog, function, year_of_construction, climate_zone):
nrel_archetypes = nrel_catalog.entries('archetypes')
for building_archetype in nrel_archetypes:
construction_period_limits = building_archetype.construction_period.split(' - ')
if construction_period_limits[1] == 'PRESENT':
construction_period_limits[1] = 3000
if int(construction_period_limits[0]) <= int(year_of_construction) < int(construction_period_limits[1]):
if (str(function) == str(building_archetype.function)) and \
(climate_zone == str(building_archetype.climate_zone)):
return building_archetype
raise KeyError('archetype not found')
@staticmethod
def _search_construction_in_archetype(archetype, construction_type):
construction_archetypes = archetype.constructions
for construction_archetype in construction_archetypes:
if str(construction_type) == str(construction_archetype.type):
return construction_archetype
return None
def _assign_values(self, thermal_zones, archetype):
for thermal_zone in thermal_zones:
thermal_zone.additional_thermal_bridge_u_value = archetype.extra_loses_due_to_thermal_bridges
thermal_zone.effective_thermal_capacity = archetype.thermal_capacity
thermal_zone.indirectly_heated_area_ratio = archetype.indirect_heated_ratio
thermal_zone.infiltration_rate_system_on = archetype.infiltration_rate_for_ventilation_system_on
thermal_zone.infiltration_rate_system_off = archetype.infiltration_rate_for_ventilation_system_off
for thermal_boundary in thermal_zone.thermal_boundaries:
construction_archetype = self._search_construction_in_archetype(archetype, thermal_boundary.type)
thermal_boundary.construction_name = construction_archetype.name
try:
thermal_boundary.window_ratio = construction_archetype.window_ratio
except ValueError:
# This is the normal operation way when the windows are defined in the geometry
continue
thermal_boundary.layers = []
for layer_archetype in construction_archetype.layers:
layer = Layer()
layer.thickness = layer_archetype.thickness
material = Material()
archetype_material = layer_archetype.material
material.name = archetype_material.name
material.id = archetype_material.id
material.no_mass = archetype_material.no_mass
if archetype_material.no_mass:
material.thermal_resistance = archetype_material.thermal_resistance
else:
material.density = archetype_material.density
material.conductivity = archetype_material.conductivity
material.specific_heat = archetype_material.specific_heat
material.solar_absorptance = archetype_material.solar_absorptance
material.thermal_absorptance = archetype_material.thermal_absorptance
material.visible_absorptance = archetype_material.visible_absorptance
layer.material = material
thermal_boundary.layers.append(layer)
# The agreement is that the layers are defined from outside to inside
external_layer = construction_archetype.layers[0]
external_surface = thermal_boundary.parent_surface
external_surface.short_wave_reflectance = 1 - float(external_layer.material.solar_absorptance)
external_surface.long_wave_emittance = 1 - float(external_layer.material.solar_absorptance)
internal_layer = construction_archetype.layers[len(construction_archetype.layers) - 1]
internal_surface = thermal_boundary.internal_surface
internal_surface.short_wave_reflectance = 1 - float(internal_layer.material.solar_absorptance)
internal_surface.long_wave_emittance = 1 - float(internal_layer.material.solar_absorptance)
for thermal_opening in thermal_boundary.thermal_openings:
if construction_archetype.window is not None:
window_archetype = construction_archetype.window
thermal_opening.construction_name = window_archetype.name
thermal_opening.frame_ratio = window_archetype.frame_ratio
thermal_opening.g_value = window_archetype.g_value
thermal_opening.overall_u_value = window_archetype.overall_u_value
# todo: verify windows
@staticmethod
def _calculate_view_factors(thermal_zone):
"""
Get thermal zone view factors matrix
:return: [[float]]
"""
total_area = 0
for thermal_boundary in thermal_zone.thermal_boundaries:
total_area += thermal_boundary.opaque_area
for thermal_opening in thermal_boundary.thermal_openings:
total_area += thermal_opening.area
view_factors_matrix = []
for thermal_boundary_1 in thermal_zone.thermal_boundaries:
values = []
for thermal_boundary_2 in thermal_zone.thermal_boundaries:
value = 0
if thermal_boundary_1.id != thermal_boundary_2.id:
value = thermal_boundary_2.opaque_area / (total_area - thermal_boundary_1.opaque_area)
values.append(value)
for thermal_boundary in thermal_zone.thermal_boundaries:
for thermal_opening in thermal_boundary.thermal_openings:
value = thermal_opening.area / (total_area - thermal_boundary_1.opaque_area)
values.append(value)
view_factors_matrix.append(values)
for thermal_boundary_1 in thermal_zone.thermal_boundaries:
values = []
for thermal_opening_1 in thermal_boundary_1.thermal_openings:
for thermal_boundary_2 in thermal_zone.thermal_boundaries:
value = thermal_boundary_2.opaque_area / (total_area - thermal_opening_1.area)
values.append(value)
for thermal_boundary in thermal_zone.thermal_boundaries:
for thermal_opening_2 in thermal_boundary.thermal_openings:
value = 0
if thermal_opening_1.id != thermal_opening_2.id:
value = thermal_opening_2.area / (total_area - thermal_opening_1.area)
values.append(value)
view_factors_matrix.append(values)
thermal_zone.view_factors_matrix = view_factors_matrix
@staticmethod
def _create_storeys(building, archetype, divide_in_storeys):
building.average_storey_height = archetype.average_storey_height
building.storeys_above_ground = 1
thermal_zones = StoreysGeneration(building, building.internal_zones[0],
divide_in_storeys=divide_in_storeys).thermal_zones
building.internal_zones[0].thermal_zones = thermal_zones

View File

@ -1,71 +0,0 @@
"""
Nrel-based interface, it reads format defined within the CERC team based on NREL structure
and enriches the city with archetypes and materials
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from hub.imports.construction.helpers.storeys_generation import StoreysGeneration
class NrelPhysicsInterface:
"""
NrelPhysicsInterface abstract class
"""
# todo: verify windows
@staticmethod
def _calculate_view_factors(thermal_zone):
"""
Get thermal zone view factors matrix
:return: [[float]]
"""
total_area = 0
for thermal_boundary in thermal_zone.thermal_boundaries:
total_area += thermal_boundary.opaque_area
for thermal_opening in thermal_boundary.thermal_openings:
total_area += thermal_opening.area
view_factors_matrix = []
for thermal_boundary_1 in thermal_zone.thermal_boundaries:
values = []
for thermal_boundary_2 in thermal_zone.thermal_boundaries:
value = 0
if thermal_boundary_1.id != thermal_boundary_2.id:
value = thermal_boundary_2.opaque_area / (total_area - thermal_boundary_1.opaque_area)
values.append(value)
for thermal_boundary in thermal_zone.thermal_boundaries:
for thermal_opening in thermal_boundary.thermal_openings:
value = thermal_opening.area / (total_area - thermal_boundary_1.opaque_area)
values.append(value)
view_factors_matrix.append(values)
for thermal_boundary_1 in thermal_zone.thermal_boundaries:
values = []
for thermal_opening_1 in thermal_boundary_1.thermal_openings:
for thermal_boundary_2 in thermal_zone.thermal_boundaries:
value = thermal_boundary_2.opaque_area / (total_area - thermal_opening_1.area)
values.append(value)
for thermal_boundary in thermal_zone.thermal_boundaries:
for thermal_opening_2 in thermal_boundary.thermal_openings:
value = 0
if thermal_opening_1.id != thermal_opening_2.id:
value = thermal_opening_2.area / (total_area - thermal_opening_1.area)
values.append(value)
view_factors_matrix.append(values)
thermal_zone.view_factors_matrix = view_factors_matrix
@staticmethod
def _create_storeys(building, archetype, divide_in_storeys):
building.average_storey_height = archetype.average_storey_height
building.storeys_above_ground = 1
thermal_zones = StoreysGeneration(building, building.internal_zones[0],
divide_in_storeys=divide_in_storeys).thermal_zones
building.internal_zones[0].thermal_zones = thermal_zones
def enrich_buildings(self):
"""
Raise not implemented error
"""
raise NotImplementedError

View File

@ -1,5 +1,5 @@
""" """
UsPhysicsParameters import the construction and material information for US NrelPhysicsParameters import the construction and material information defined by NREL
SPDX - License - Identifier: LGPL - 3.0 - or -later SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
@ -7,38 +7,41 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord
""" """
import sys import sys
from hub.imports.construction.nrel_physics_interface import NrelPhysicsInterface from hub.hub_logger import logger
from hub.catalog_factories.construction_catalog_factory import ConstructionCatalogFactory from hub.catalog_factories.construction_catalog_factory import ConstructionCatalogFactory
from hub.city_model_structure.building_demand.layer import Layer from hub.city_model_structure.building_demand.layer import Layer
from hub.city_model_structure.building_demand.material import Material from hub.city_model_structure.building_demand.material import Material
from hub.helpers.dictionaries import Dictionaries
from hub.imports.construction.helpers.construction_helper import ConstructionHelper from hub.imports.construction.helpers.construction_helper import ConstructionHelper
from hub.hub_logger import logger from hub.imports.construction.helpers.storeys_generation import StoreysGeneration
class UsPhysicsParameters(NrelPhysicsInterface): class NrelPhysicsParameters:
""" """
UsPhysicsParameters class NrelPhysicsParameters class
""" """
def __init__(self, city, base_path, divide_in_storeys=False): def __init__(self, city, base_path, divide_in_storeys=False):
self._city = city self._city = city
self._path = base_path self._path = base_path
self._divide_in_storeys = divide_in_storeys self._divide_in_storeys = divide_in_storeys
self._climate_zone = ConstructionHelper.city_to_nrel_climate_zone(city.name) self._climate_zone = ConstructionHelper.city_to_nrel_climate_zone(city.name)
super().__init__()
def enrich_buildings(self): def enrich_buildings(self):
""" """
Returns the city with the construction parameters assigned to the buildings Returns the city with the construction parameters assigned to the buildings
""" """
city = self._city city = self._city
nrel_catalog = ConstructionCatalogFactory('nrel').catalog
for building in city.buildings: for building in city.buildings:
try: try:
archetype = self._search_archetype(building.function, building.year_of_construction, self._climate_zone) 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: except KeyError:
logger.error(f'Building {building.name} has unknown archetype for building function: {building.function} ' logger.error(f'Building {building.name} has unknown archetype for building function: {building.function} '
f'and building year of construction: {building.year_of_construction} ' f'and building year of construction: {building.year_of_construction} '
f'and climate zone reference norm {self._climate_zone}\n') f'and climate zone reference norm {self._climate_zone}\n')
sys.stderr.write(f'Building {building.name} has unknown archetype for building function: {building.function} ' sys.stderr.write(f'Building {building.name} has unknown archetype for building function: {building.function} '
f'and building year of construction: {building.year_of_construction} ' f'and building year of construction: {building.year_of_construction} '
f'and climate zone reference norm {self._climate_zone}\n') f'and climate zone reference norm {self._climate_zone}\n')
@ -69,8 +72,7 @@ class UsPhysicsParameters(NrelPhysicsInterface):
self._calculate_view_factors(thermal_zone) self._calculate_view_factors(thermal_zone)
@staticmethod @staticmethod
def _search_archetype(function, year_of_construction, climate_zone): def _search_archetype(nrel_catalog, function, year_of_construction, climate_zone):
nrel_catalog = ConstructionCatalogFactory('nrel').catalog
nrel_archetypes = nrel_catalog.entries('archetypes') nrel_archetypes = nrel_catalog.entries('archetypes')
for building_archetype in nrel_archetypes: for building_archetype in nrel_archetypes:
construction_period_limits = building_archetype.construction_period.split(' - ') construction_period_limits = building_archetype.construction_period.split(' - ')
@ -142,3 +144,53 @@ class UsPhysicsParameters(NrelPhysicsInterface):
thermal_opening.frame_ratio = window_archetype.frame_ratio thermal_opening.frame_ratio = window_archetype.frame_ratio
thermal_opening.g_value = window_archetype.g_value thermal_opening.g_value = window_archetype.g_value
thermal_opening.overall_u_value = window_archetype.overall_u_value thermal_opening.overall_u_value = window_archetype.overall_u_value
# todo: verify windows
@staticmethod
def _calculate_view_factors(thermal_zone):
"""
Get thermal zone view factors matrix
:return: [[float]]
"""
total_area = 0
for thermal_boundary in thermal_zone.thermal_boundaries:
total_area += thermal_boundary.opaque_area
for thermal_opening in thermal_boundary.thermal_openings:
total_area += thermal_opening.area
view_factors_matrix = []
for thermal_boundary_1 in thermal_zone.thermal_boundaries:
values = []
for thermal_boundary_2 in thermal_zone.thermal_boundaries:
value = 0
if thermal_boundary_1.id != thermal_boundary_2.id:
value = thermal_boundary_2.opaque_area / (total_area - thermal_boundary_1.opaque_area)
values.append(value)
for thermal_boundary in thermal_zone.thermal_boundaries:
for thermal_opening in thermal_boundary.thermal_openings:
value = thermal_opening.area / (total_area - thermal_boundary_1.opaque_area)
values.append(value)
view_factors_matrix.append(values)
for thermal_boundary_1 in thermal_zone.thermal_boundaries:
values = []
for thermal_opening_1 in thermal_boundary_1.thermal_openings:
for thermal_boundary_2 in thermal_zone.thermal_boundaries:
value = thermal_boundary_2.opaque_area / (total_area - thermal_opening_1.area)
values.append(value)
for thermal_boundary in thermal_zone.thermal_boundaries:
for thermal_opening_2 in thermal_boundary.thermal_openings:
value = 0
if thermal_opening_1.id != thermal_opening_2.id:
value = thermal_opening_2.area / (total_area - thermal_opening_1.area)
values.append(value)
view_factors_matrix.append(values)
thermal_zone.view_factors_matrix = view_factors_matrix
@staticmethod
def _create_storeys(building, archetype, divide_in_storeys):
building.average_storey_height = archetype.average_storey_height
building.storeys_above_ground = 1
thermal_zones = StoreysGeneration(building, building.internal_zones[0],
divide_in_storeys=divide_in_storeys).thermal_zones
building.internal_zones[0].thermal_zones = thermal_zones

View File

@ -3,19 +3,29 @@ ConstructionFactory (before PhysicsFactory) retrieve the specific construction m
SPDX - License - Identifier: LGPL - 3.0 - or -later SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
from pathlib import Path from pathlib import Path
from hub.imports.construction.us_physics_parameters import UsPhysicsParameters from hub.hub_logger import logger
from hub.helpers.utils import validate_import_export_type
from hub.imports.construction.nrel_physics_parameters import NrelPhysicsParameters
from hub.imports.construction.nrcan_physics_parameters import NrcanPhysicsParameters
class ConstructionFactory: class ConstructionFactory:
""" """
PhysicsFactor class ConstructionFactory class
""" """
def __init__(self, handler, city, base_path=None): def __init__(self, handler, city, base_path=None):
if base_path is None: if base_path is None:
base_path = Path(Path(__file__).parent.parent / 'data/construction') base_path = Path(Path(__file__).parent.parent / 'data/construction')
self._handler = '_' + handler.lower().replace(' ', '_') self._handler = '_' + handler.lower().replace(' ', '_')
class_funcs = validate_import_export_type(ConstructionFactory)
if self._handler not in class_funcs:
err_msg = f"Wrong import type [{self._handler}]. Valid functions include {class_funcs}"
logger.error(err_msg)
raise Exception(err_msg)
self._city = city self._city = city
self._base_path = base_path self._base_path = base_path
@ -23,7 +33,14 @@ class ConstructionFactory:
""" """
Enrich the city by using NREL information Enrich the city by using NREL information
""" """
UsPhysicsParameters(self._city, self._base_path).enrich_buildings() NrelPhysicsParameters(self._city, self._base_path).enrich_buildings()
self._city.level_of_detail.construction = 2
def _nrcan(self):
"""
Enrich the city by using NRCAN information
"""
NrcanPhysicsParameters(self._city, self._base_path).enrich_buildings()
self._city.level_of_detail.construction = 2 self._city.level_of_detail.construction = 2
def enrich(self): def enrich(self):
@ -38,4 +55,4 @@ class ConstructionFactory:
Enrich the city given to the class using the class given handler Enrich the city given to the class using the class given handler
:return: None :return: None
""" """
UsPhysicsParameters(self._city, self._base_path).enrich_buildings() NrelPhysicsParameters(self._city, self._base_path).enrich_buildings()

View File

@ -4,10 +4,9 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group Copyright © 2022 Concordia CERC group
Project CoderPeter Yefi peteryefi@gmail.com Project CoderPeter Yefi peteryefi@gmail.com
""" """
from hub.persistence import CityRepo
from hub.persistence import HeatPumpSimulationRepo
from typing import Dict
from hub.city_model_structure.city import City from hub.city_model_structure.city import City
from hub.persistence import City as CityRepository
from hub.persistence import SimulationResults
class DBFactory: class DBFactory:
@ -16,14 +15,18 @@ class DBFactory:
""" """
def __init__(self, db_name, dotenv_path, app_env): def __init__(self, db_name, dotenv_path, app_env):
self._city_repo = CityRepo(db_name=db_name, dotenv_path=dotenv_path, app_env=app_env) self._city_repository = CityRepository(db_name=db_name, dotenv_path=dotenv_path, app_env=app_env)
self._hp_simulation_repo = HeatPumpSimulationRepo(db_name=db_name, dotenv_path=dotenv_path, app_env=app_env) self._simulation_results = SimulationResults(db_name=db_name, dotenv_path=dotenv_path, app_env=app_env)
def persist_city(self, user_id: int, city: City): def persist_city(self, city: City, pickle_path, application_id: int, user_id: int):
""" """
Persist city into postgres database Persist city into postgres database
:param city: City to be stored
:param pickle_path: Path to save the pickle file
:param application_id: Application id owning this city
:param user_id: User who create the city
""" """
return self._city_repo.insert(city, user_id) return self._city_repository.insert(city, pickle_path, application_id, user_id)
def update_city(self, city_id, city): def update_city(self, city_id, city):
""" """
@ -31,27 +34,21 @@ class DBFactory:
:param city_id: the id of the city to update :param city_id: the id of the city to update
:param city: the updated city object :param city: the updated city object
""" """
return self._city_repo.update(city_id, city) return self._city_repository.update(city_id, city)
def delete_city(self, city_id): def delete_city(self, city_id):
""" """
Deletes a single city from postgres Deletes a single city from postgres
:param city_id: the id of the city to get :param city_id: the id of the city to get
""" """
self._city_repo.delete_city(city_id) self._city_repository.delete(city_id)
def persist_hp_simulation(self, hp_simulation_data: Dict, city_id: int): def add_simulation_results(self, name, values, city_id=None, city_object_id=None):
""" """
Persist heat pump simulation results Add simulation results to the city or to the city_object
:param hp_simulation_data: the simulation results :param name: simulation and simulation engine name
:param city_id: the city object used in running the simulation :param values: simulation values in json format
:return: HeatPumpSimulation object :param city_id: city id or None
:param city_object_id: city object id or None
""" """
return self._hp_simulation_repo.insert(hp_simulation_data, city_id) self._simulation_results.insert(name, values,city_id, city_object_id)
def delete_hp_simulation(self, hp_sim_id):
"""
Deletes a single heat pump simulation from postgres
:param hp_sim_id: the id of the heat pump simulation to get
"""
self._hp_simulation_repo.delete_hp_simulation(hp_sim_id)

View File

@ -2,7 +2,8 @@
AirSourceHeatPumpParameters import the heat pump information AirSourceHeatPumpParameters import the heat pump information
SPDX - License - Identifier: LGPL - 3.0 - or -later SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group Copyright © 2022 Concordia CERC group
Project Coder Peter Yefi peteryefi@gmail.comCode contributor Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca Project Coder Peter Yefi peteryefi@gmail.comCode
contributor Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
import pandas as pd import pandas as pd
@ -41,7 +42,7 @@ class AirSourceHeatPumpParameters:
for sheet, dataframe in heat_pump_dfs.items(): for sheet, dataframe in heat_pump_dfs.items():
if 'Summary' in sheet: if 'Summary' in sheet:
continue continue
# Remove nan rows and columns and extract cooling and heating data # Remove nan rows and columns and extract cooling and heating data
# for each sheet # for each sheet
@ -69,8 +70,7 @@ class AirSourceHeatPumpParameters:
Enriches the city with information from file Enriches the city with information from file
""" """
heat_pump_data = self._read_file() heat_pump_data = self._read_file()
for (k_cool, v_cool), (k_heat, v_heat) in \ for (k_cool, v_cool), (k_heat, v_heat) in zip(heat_pump_data["cooling"].items(), heat_pump_data["heating"].items()):
zip(heat_pump_data["cooling"].items(), heat_pump_data["heating"].items()):
heat_pump = AirSourceHP() heat_pump = AirSourceHP()
heat_pump.model = k_cool heat_pump.model = k_cool
h_data = self._extract_heat_pump_data(v_heat) h_data = self._extract_heat_pump_data(v_heat)
@ -87,7 +87,8 @@ class AirSourceHeatPumpParameters:
self._city.add_city_object(energy_system) self._city.add_city_object(energy_system)
return self._city return self._city
def _extract_heat_pump_data(self, heat_pump_capacity_data: Dict) -> [List, List]: @staticmethod
def _extract_heat_pump_data(heat_pump_capacity_data: Dict) -> [List, List]:
""" """
Fetches a list of metric based data for heat pump for various temperature, Fetches a list of metric based data for heat pump for various temperature,
eg. cooling capacity data for 12 capacity heat pump eg. cooling capacity data for 12 capacity heat pump
@ -123,15 +124,16 @@ class AirSourceHeatPumpParameters:
x_values = x_values.tolist() x_values = x_values.tolist()
# convert list of lists to one list # convert list of lists to one list
hp_data = [i/j for i, j in hp_data = [i / j for i, j in
zip(list(itertools.chain.from_iterable(heat_pump_data[0])), zip(list(itertools.chain.from_iterable(heat_pump_data[0])),
list(itertools.chain.from_iterable(heat_pump_data[1])))] list(itertools.chain.from_iterable(heat_pump_data[1])))]
# Compute heat output coefficients # Compute heat output coefficients
popt, _ = curve_fit(self._objective_function, [x_values, out_temp], hp_data) popt, _ = curve_fit(self._objective_function, [x_values, out_temp], hp_data)
return popt.tolist() return popt.tolist()
def _objective_function(self, xdata: List, a1: float, a2: float, a3: float, a4: float, a5: float, a6: float) -> float: @staticmethod
def _objective_function(xdata: List, a1: float, a2: float, a3: float, a4: float, a5: float, a6: float) -> float:
""" """
Objective function for computing coefficients Objective function for computing coefficients
:param xdata: :param xdata:

View File

@ -71,7 +71,8 @@ class WaterToWaterHPParameters:
# range values for extracting data # range values for extracting data
return data return data
def _extract_hp_data(self, df, columns, ranges): @staticmethod
def _extract_hp_data(df, columns, ranges):
""" """
Extract variable specific (LWT, PD or TC) data from water to water hp Extract variable specific (LWT, PD or TC) data from water to water hp
:param df: the dataframe :param df: the dataframe
@ -88,7 +89,8 @@ class WaterToWaterHPParameters:
return data.dropna().values.tolist() return data.dropna().values.tolist()
def _extract_flow_and_ewt(self, df, ranges, columns, flow_rates): @staticmethod
def _extract_flow_and_ewt(df, ranges, columns, flow_rates):
""" """
Create the flow and ewt data based on the length of the various Create the flow and ewt data based on the length of the various
columns for the variables being extracted columns for the variables being extracted
@ -148,7 +150,8 @@ class WaterToWaterHPParameters:
demand) demand)
return popt.tolist() return popt.tolist()
def _objective_function(self, xdata: List, a1: float, a2: float, a3: float, a4: float, a5: float, a6: float, @staticmethod
def _objective_function(xdata: List, a1: float, a2: float, a3: float, a4: float, a5: float, a6: float,
a7: float, a8: float, a9: float, a10: float, a11: float) -> float: a7: float, a8: float, a9: float, a10: float, a11: float) -> float:
""" """
Objective function for computing coefficients Objective function for computing coefficients
@ -169,4 +172,3 @@ class WaterToWaterHPParameters:
x, y, t = xdata x, y, t = xdata
return (a1 * x ** 2) + (a2 * x) + (a3 * y ** 2) + (a4 * y) + (a5 * t ** 2) + (a6 * t) + (a7 * x * y) + ( return (a1 * x ** 2) + (a2 * x) + (a3 * y ** 2) + (a4 * y) + (a5 * t ** 2) + (a6 * t) + (a7 * x * y) + (
a8 * x * t) + (a9 * y * t) + (a10 * x * y * t) + a11 a8 * x * t) + (a9 * y * t) + (a10 * x * y * t) + a11

View File

@ -8,6 +8,8 @@ Code contributors: Peter Yefi peteryefi@gmail.com
from pathlib import Path from pathlib import Path
from hub.imports.energy_systems.air_source_hp_parameters import AirSourceHeatPumpParameters from hub.imports.energy_systems.air_source_hp_parameters import AirSourceHeatPumpParameters
from hub.imports.energy_systems.water_to_water_hp_parameters import WaterToWaterHPParameters 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 logger
class EnergySystemsFactory: class EnergySystemsFactory:
@ -19,6 +21,11 @@ class EnergySystemsFactory:
if base_path is None: if base_path is None:
base_path = Path(Path(__file__).parent.parent / 'data/energy_systems') base_path = Path(Path(__file__).parent.parent / 'data/energy_systems')
self._handler = '_' + handler.lower().replace(' ', '_') self._handler = '_' + handler.lower().replace(' ', '_')
class_funcs = validate_import_export_type(EnergySystemsFactory)
if self._handler not in class_funcs:
err_msg = f"Wrong import type. Valid functions include {class_funcs}"
logger.error(err_msg)
raise Exception(err_msg)
self._city = city self._city = city
self._base_path = base_path self._base_path = base_path

View File

@ -7,26 +7,35 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
import numpy as np import numpy as np
import xmltodict import xmltodict
from hub.city_model_structure.city import City
from hub.city_model_structure.building import Building from hub.city_model_structure.building import Building
from hub.city_model_structure.city import City
from hub.city_model_structure.parts_consisting_building import PartsConsistingBuilding from hub.city_model_structure.parts_consisting_building import PartsConsistingBuilding
from hub.helpers.geometry_helper import GeometryHelper
from hub.imports.geometry.citygml_classes.citygml_lod2 import CityGmlLod2
from hub.imports.geometry.citygml_classes.citygml_lod1 import CityGmlLod1 from hub.imports.geometry.citygml_classes.citygml_lod1 import CityGmlLod1
from hub.imports.geometry.citygml_classes.citygml_lod2 import CityGmlLod2
class CityGml: class CityGml:
""" """
CityGml class CityGml class
""" """
def __init__(self, path, extrusion_height_field=None, year_of_construction_field=None, function_field=None): def __init__(self,
path,
extrusion_height_field=None,
year_of_construction_field='yearOfConstruction',
function_field='function',
function_to_hub=None):
self._city = None self._city = None
self._lod = None self._lod = None
self._lod1_tags = ['lod1Solid', 'lod1MultiSurface'] self._lod1_tags = ['lod1Solid', 'lod1MultiSurface']
self._lod2_tags = ['lod2Solid', 'lod2MultiSurface', 'lod2MultiCurve'] self._lod2_tags = ['lod2Solid', 'lod2MultiSurface', 'lod2MultiCurve']
self._extrusion_height_field = extrusion_height_field self._extrusion_height_field = extrusion_height_field
self._function_to_hub = function_to_hub
self._year_of_construction_field = year_of_construction_field self._year_of_construction_field = year_of_construction_field
if function_field is None:
function_field = 'function'
self._function_field = function_field self._function_field = function_field
self._lower_corner = None self._lower_corner = None
self._upper_corner = None self._upper_corner = None
with open(path) as gml: with open(path) as gml:
@ -54,7 +63,6 @@ class CityGml:
}, force_list=force_list) }, force_list=force_list)
self._city_objects = None self._city_objects = None
self._geometry = GeometryHelper()
if 'boundedBy' in self._gml['CityModel']: if 'boundedBy' in self._gml['CityModel']:
for bound in self._gml['CityModel']['boundedBy']: for bound in self._gml['CityModel']['boundedBy']:
envelope = bound['Envelope'] envelope = bound['Envelope']
@ -108,10 +116,16 @@ class CityGml:
name = city_object['@id'] name = city_object['@id']
function = None function = None
year_of_construction = None year_of_construction = None
if 'yearOfConstruction' in city_object: if self._year_of_construction_field in city_object:
year_of_construction = city_object['yearOfConstruction'] year_of_construction = city_object[self._year_of_construction_field]
if 'function' in city_object: if self._function_field in city_object:
function = city_object['function'] function = city_object[self._function_field]
if type(function) != str:
function = function['#text']
if self._function_to_hub is not None:
# use the transformation dictionary to retrieve the proper function
function = self._function_to_hub[function]
if any(key in city_object for key in self._lod1_tags): if any(key in city_object for key in self._lod1_tags):
if self._lod is None or self._lod > 1: if self._lod is None or self._lod > 1:
self._lod = 1 self._lod = 1

View File

@ -26,7 +26,12 @@ class Geojson:
X = 0 X = 0
Y = 1 Y = 1
def __init__(self, path, extrusion_height_field=None, year_of_construction_field=None, function_field=None): def __init__(self,
path,
extrusion_height_field=None,
year_of_construction_field=None,
function_field=None,
function_to_hub=None):
# todo: destination epsg should change according actual the location # todo: destination epsg should change according actual the location
self._transformer = Transformer.from_crs('epsg:4326', 'epsg:26911') self._transformer = Transformer.from_crs('epsg:4326', 'epsg:26911')
self._min_x = cte.MAX_FLOAT self._min_x = cte.MAX_FLOAT
@ -38,6 +43,7 @@ class Geojson:
self._extrusion_height_field = extrusion_height_field self._extrusion_height_field = extrusion_height_field
self._year_of_construction_field = year_of_construction_field self._year_of_construction_field = year_of_construction_field
self._function_field = function_field self._function_field = function_field
self._function_to_hub = function_to_hub
with open(path) as json_file: with open(path) as json_file:
self._geojson = json.loads(json_file.read()) self._geojson = json.loads(json_file.read())
@ -118,6 +124,9 @@ class Geojson:
function = None function = None
if self._function_field is not None: if self._function_field is not None:
function = feature['properties'][self._function_field] function = feature['properties'][self._function_field]
if self._function_to_hub is not None:
# use the transformation dictionary to retrieve the proper function
function = self._function_to_hub[function]
geometry = feature['geometry'] geometry = feature['geometry']
if 'id' in feature: if 'id' in feature:
building_name = feature['id'] building_name = feature['id']
@ -125,6 +134,7 @@ class Geojson:
building_name = f'building_{building_id}' building_name = f'building_{building_id}'
building_id += 1 building_id += 1
polygons = [] polygons = []
lod = 1
for part, coordinates in enumerate(geometry['coordinates']): for part, coordinates in enumerate(geometry['coordinates']):
polygons = self._get_polygons(polygons, coordinates) polygons = self._get_polygons(polygons, coordinates)
for zone, polygon in enumerate(polygons): for zone, polygon in enumerate(polygons):
@ -133,6 +143,7 @@ class Geojson:
year_of_construction, year_of_construction,
function, function,
[polygon]) [polygon])
lod = 0
else: else:
if self._max_z < extrusion_height: if self._max_z < extrusion_height:
self._max_z = extrusion_height self._max_z = extrusion_height
@ -145,4 +156,5 @@ class Geojson:
self._city = City([self._min_x, self._min_y, 0.0], [self._max_x, self._max_y, self._max_z], 'epsg:26911') self._city = City([self._min_x, self._min_y, 0.0], [self._max_x, self._max_y, self._max_z], 'epsg:26911')
for building in buildings: for building in buildings:
self._city.add_city_object(building) self._city.add_city_object(building)
self._city.level_of_detail.geometry = lod
return self._city return self._city

View File

@ -57,6 +57,7 @@ class GPandas:
""" """
if self._city is None: if self._city is None:
self._city = City(self._lower_corner, self._upper_corner, self._srs_name) self._city = City(self._lower_corner, self._upper_corner, self._srs_name)
lod = 0
for scene_index, bldg in self._scene.iterrows(): for scene_index, bldg in self._scene.iterrows():
polygon = bldg.geometry polygon = bldg.geometry
height = float(bldg['height']) height = float(bldg['height'])

View File

@ -5,7 +5,6 @@ Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
import hub.helpers.constants as cte
import numpy as np import numpy as np
@ -13,276 +12,6 @@ class GeometryHelper:
""" """
Geometry helper Geometry helper
""" """
# function
_pluto_to_function = {
'A0': cte.SINGLE_FAMILY_HOUSE,
'A1': cte.SINGLE_FAMILY_HOUSE,
'A2': cte.SINGLE_FAMILY_HOUSE,
'A3': cte.SINGLE_FAMILY_HOUSE,
'A4': cte.SINGLE_FAMILY_HOUSE,
'A5': cte.SINGLE_FAMILY_HOUSE,
'A6': cte.SINGLE_FAMILY_HOUSE,
'A7': cte.SINGLE_FAMILY_HOUSE,
'A8': cte.SINGLE_FAMILY_HOUSE,
'A9': cte.SINGLE_FAMILY_HOUSE,
'B1': cte.MULTI_FAMILY_HOUSE,
'B2': cte.MULTI_FAMILY_HOUSE,
'B3': cte.MULTI_FAMILY_HOUSE,
'B9': cte.MULTI_FAMILY_HOUSE,
'C0': cte.RESIDENTIAL,
'C1': cte.RESIDENTIAL,
'C2': cte.RESIDENTIAL,
'C3': cte.RESIDENTIAL,
'C4': cte.RESIDENTIAL,
'C5': cte.RESIDENTIAL,
'C6': cte.RESIDENTIAL,
'C7': cte.RESIDENTIAL,
'C8': cte.RESIDENTIAL,
'C9': cte.RESIDENTIAL,
'D0': cte.RESIDENTIAL,
'D1': cte.RESIDENTIAL,
'D2': cte.RESIDENTIAL,
'D3': cte.RESIDENTIAL,
'D4': cte.RESIDENTIAL,
'D5': cte.RESIDENTIAL,
'D6': cte.RESIDENTIAL,
'D7': cte.RESIDENTIAL,
'D8': cte.RESIDENTIAL,
'D9': cte.RESIDENTIAL,
'E1': cte.WAREHOUSE,
'E3': cte.WAREHOUSE,
'E4': cte.WAREHOUSE,
'E5': cte.WAREHOUSE,
'E7': cte.WAREHOUSE,
'E9': cte.WAREHOUSE,
'F1': cte.WAREHOUSE,
'F2': cte.WAREHOUSE,
'F4': cte.WAREHOUSE,
'F5': cte.WAREHOUSE,
'F8': cte.WAREHOUSE,
'F9': cte.WAREHOUSE,
'G0': cte.SMALL_OFFICE,
'G1': cte.SMALL_OFFICE,
'G2': cte.SMALL_OFFICE,
'G3': cte.SMALL_OFFICE,
'G4': cte.SMALL_OFFICE,
'G5': cte.SMALL_OFFICE,
'G6': cte.SMALL_OFFICE,
'G7': cte.SMALL_OFFICE,
'G8': cte.SMALL_OFFICE,
'G9': cte.SMALL_OFFICE,
'H1': cte.HOTEL,
'H2': cte.HOTEL,
'H3': cte.HOTEL,
'H4': cte.HOTEL,
'H5': cte.HOTEL,
'H6': cte.HOTEL,
'H7': cte.HOTEL,
'H8': cte.HOTEL,
'H9': cte.HOTEL,
'HB': cte.HOTEL,
'HH': cte.HOTEL,
'HR': cte.HOTEL,
'HS': cte.HOTEL,
'I1': cte.HOSPITAL,
'I2': cte.OUT_PATIENT_HEALTH_CARE,
'I3': cte.OUT_PATIENT_HEALTH_CARE,
'I4': cte.RESIDENTIAL,
'I5': cte.OUT_PATIENT_HEALTH_CARE,
'I6': cte.OUT_PATIENT_HEALTH_CARE,
'I7': cte.OUT_PATIENT_HEALTH_CARE,
'I9': cte.OUT_PATIENT_HEALTH_CARE,
'J1': cte.LARGE_OFFICE,
'J2': cte.LARGE_OFFICE,
'J3': cte.LARGE_OFFICE,
'J4': cte.LARGE_OFFICE,
'J5': cte.LARGE_OFFICE,
'J6': cte.LARGE_OFFICE,
'J7': cte.LARGE_OFFICE,
'J8': cte.LARGE_OFFICE,
'J9': cte.LARGE_OFFICE,
'K1': cte.STRIP_MALL,
'K2': cte.STRIP_MALL,
'K3': cte.STRIP_MALL,
'K4': cte.RESIDENTIAL,
'K5': cte.RESTAURANT,
'K6': cte.SUPERMARKET,
'K7': cte.SUPERMARKET,
'K8': cte.SUPERMARKET,
'K9': cte.SUPERMARKET,
'L1': cte.RESIDENTIAL,
'L2': cte.RESIDENTIAL,
'L3': cte.RESIDENTIAL,
'L8': cte.RESIDENTIAL,
'L9': cte.RESIDENTIAL,
'M1': cte.LARGE_OFFICE,
'M2': cte.LARGE_OFFICE,
'M3': cte.LARGE_OFFICE,
'M4': cte.LARGE_OFFICE,
'M9': cte.LARGE_OFFICE,
'N1': cte.RESIDENTIAL,
'N2': cte.RESIDENTIAL,
'N3': cte.RESIDENTIAL,
'N4': cte.RESIDENTIAL,
'N9': cte.RESIDENTIAL,
'O1': cte.SMALL_OFFICE,
'O2': cte.SMALL_OFFICE,
'O3': cte.SMALL_OFFICE,
'O4': cte.SMALL_OFFICE,
'O5': cte.SMALL_OFFICE,
'O6': cte.SMALL_OFFICE,
'O7': cte.SMALL_OFFICE,
'O8': cte.SMALL_OFFICE,
'O9': cte.SMALL_OFFICE,
'P1': cte.LARGE_OFFICE,
'P2': cte.HOTEL,
'P3': cte.SMALL_OFFICE,
'P4': cte.SMALL_OFFICE,
'P5': cte.SMALL_OFFICE,
'P6': cte.SMALL_OFFICE,
'P7': cte.LARGE_OFFICE,
'P8': cte.LARGE_OFFICE,
'P9': cte.SMALL_OFFICE,
'Q0': cte.SMALL_OFFICE,
'Q1': cte.SMALL_OFFICE,
'Q2': cte.SMALL_OFFICE,
'Q3': cte.SMALL_OFFICE,
'Q4': cte.SMALL_OFFICE,
'Q5': cte.SMALL_OFFICE,
'Q6': cte.SMALL_OFFICE,
'Q7': cte.SMALL_OFFICE,
'Q8': cte.SMALL_OFFICE,
'Q9': cte.SMALL_OFFICE,
'R0': cte.RESIDENTIAL,
'R1': cte.RESIDENTIAL,
'R2': cte.RESIDENTIAL,
'R3': cte.RESIDENTIAL,
'R4': cte.RESIDENTIAL,
'R5': cte.RESIDENTIAL,
'R6': cte.RESIDENTIAL,
'R7': cte.RESIDENTIAL,
'R8': cte.RESIDENTIAL,
'R9': cte.RESIDENTIAL,
'RA': cte.RESIDENTIAL,
'RB': cte.RESIDENTIAL,
'RC': cte.RESIDENTIAL,
'RD': cte.RESIDENTIAL,
'RG': cte.RESIDENTIAL,
'RH': cte.RESIDENTIAL,
'RI': cte.RESIDENTIAL,
'RK': cte.RESIDENTIAL,
'RM': cte.RESIDENTIAL,
'RR': cte.RESIDENTIAL,
'RS': cte.RESIDENTIAL,
'RW': cte.RESIDENTIAL,
'RX': cte.RESIDENTIAL,
'RZ': cte.RESIDENTIAL,
'S0': cte.RESIDENTIAL,
'S1': cte.RESIDENTIAL,
'S2': cte.RESIDENTIAL,
'S3': cte.RESIDENTIAL,
'S4': cte.RESIDENTIAL,
'S5': cte.RESIDENTIAL,
'S9': cte.RESIDENTIAL,
'U0': cte.WAREHOUSE,
'U1': cte.WAREHOUSE,
'U2': cte.WAREHOUSE,
'U3': cte.WAREHOUSE,
'U4': cte.WAREHOUSE,
'U5': cte.WAREHOUSE,
'U6': cte.WAREHOUSE,
'U7': cte.WAREHOUSE,
'U8': cte.WAREHOUSE,
'U9': cte.WAREHOUSE,
'W1': cte.PRIMARY_SCHOOL,
'W2': cte.PRIMARY_SCHOOL,
'W3': cte.SECONDARY_SCHOOL,
'W4': cte.SECONDARY_SCHOOL,
'W5': cte.SECONDARY_SCHOOL,
'W6': cte.SECONDARY_SCHOOL,
'W7': cte.SECONDARY_SCHOOL,
'W8': cte.PRIMARY_SCHOOL,
'W9': cte.SECONDARY_SCHOOL,
'Y1': cte.LARGE_OFFICE,
'Y2': cte.LARGE_OFFICE,
'Y3': cte.LARGE_OFFICE,
'Y4': cte.LARGE_OFFICE,
'Y5': cte.LARGE_OFFICE,
'Y6': cte.LARGE_OFFICE,
'Y7': cte.LARGE_OFFICE,
'Y8': cte.LARGE_OFFICE,
'Y9': cte.LARGE_OFFICE,
'Z1': cte.LARGE_OFFICE
}
_hft_to_function = {
'residential': cte.RESIDENTIAL,
'single family house': cte.SINGLE_FAMILY_HOUSE,
'multifamily house': cte.MULTI_FAMILY_HOUSE,
'hotel': cte.HOTEL,
'hospital': cte.HOSPITAL,
'outpatient': cte.OUT_PATIENT_HEALTH_CARE,
'commercial': cte.SUPERMARKET,
'strip mall': cte.STRIP_MALL,
'warehouse': cte.WAREHOUSE,
'primary school': cte.PRIMARY_SCHOOL,
'secondary school': cte.SECONDARY_SCHOOL,
'office': cte.MEDIUM_OFFICE,
'large office': cte.LARGE_OFFICE
}
# usage
_function_to_usage = {
cte.RESIDENTIAL: cte.RESIDENTIAL,
cte.SINGLE_FAMILY_HOUSE: cte.SINGLE_FAMILY_HOUSE,
cte.MULTI_FAMILY_HOUSE: cte.MULTI_FAMILY_HOUSE,
cte.ROW_HOSE: cte.RESIDENTIAL,
cte.MID_RISE_APARTMENT: cte.RESIDENTIAL,
cte.HIGH_RISE_APARTMENT: cte.RESIDENTIAL,
cte.SMALL_OFFICE: cte.OFFICE_AND_ADMINISTRATION,
cte.MEDIUM_OFFICE: cte.OFFICE_AND_ADMINISTRATION,
cte.LARGE_OFFICE: cte.OFFICE_AND_ADMINISTRATION,
cte.PRIMARY_SCHOOL: cte.EDUCATION,
cte.SECONDARY_SCHOOL: cte.EDUCATION,
cte.STAND_ALONE_RETAIL: cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
cte.HOSPITAL: cte.HEALTH_CARE,
cte.OUT_PATIENT_HEALTH_CARE: cte.HEALTH_CARE,
cte.STRIP_MALL: cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
cte.SUPERMARKET: cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD,
cte.WAREHOUSE: cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
cte.QUICK_SERVICE_RESTAURANT: cte.RESTAURANT,
cte.FULL_SERVICE_RESTAURANT: cte.RESTAURANT,
cte.SMALL_HOTEL: cte.HOTEL,
cte.LARGE_HOTEL: cte.HOTEL,
cte.INDUSTRY:cte.INDUSTRY
}
@staticmethod
def libs_function_from_hft(building_hft_function):
"""
Get internal function from the given HfT function
:param building_hft_function: str
:return: str
"""
return GeometryHelper._hft_to_function[building_hft_function]
@staticmethod
def libs_function_from_pluto(building_pluto_function):
"""
Get internal function from the given pluto function
:param building_pluto_function: str
:return: str
"""
return GeometryHelper._pluto_to_function[building_pluto_function]
@staticmethod
def libs_usage_from_libs_function(building_function):
"""
Get the internal usage for the given internal building function
:param building_function: str
:return: str
"""
return GeometryHelper._function_to_usage[building_function]
@staticmethod @staticmethod
def to_points_matrix(points): def to_points_matrix(points):
""" """

View File

@ -51,6 +51,7 @@ class Obj:
""" """
Get city out of an obj file Get city out of an obj file
""" """
lod = 0
if self._city is None: if self._city is None:
# todo: refactor this method to clearly choose the obj type # todo: refactor this method to clearly choose the obj type
# todo: where do we get this information from? # todo: where do we get this information from?

View File

@ -1,58 +0,0 @@
"""
OsmSubway module parses osm files and import the metro location into the city model structure
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
import sys
import xmltodict
from pyproj import Transformer
from hub.city_model_structure.city import City
from hub.city_model_structure.subway_entrance import SubwayEntrance
class OsmSubway:
"""
Open street map subway
"""
def __init__(self, path):
self._city = None
self._subway_entrances = []
with open(path) as osm:
self._osm = xmltodict.parse(osm.read(), force_list='tag')
for node in self._osm['osm']['node']:
if 'tag' not in node:
continue
for tag in node['tag']:
if '@v' not in tag:
continue
if tag['@v'] == 'subway_entrance':
subway_entrance = SubwayEntrance(node['@id'], node['@lat'], node['@lon'])
self._subway_entrances.append(subway_entrance)
@property
def city(self) -> City:
"""
Get a city with subway entrances
"""
transformer = Transformer.from_crs("EPSG:4326", "EPSG:3857")
lower_corner = [sys.float_info.max, sys.float_info.max, 0]
upper_corner = [sys.float_info.min, sys.float_info.min, 0]
x = 0
y = 1
for subway_entrance in self._subway_entrances:
coordinate = transformer.transform(subway_entrance.longitude, subway_entrance.latitude)
if coordinate[x] >= upper_corner[x]:
upper_corner[x] = coordinate[x]
if coordinate[y] >= upper_corner[y]:
upper_corner[y] = coordinate[y]
if coordinate[x] < lower_corner[x]:
lower_corner[x] = coordinate[x]
if coordinate[y] < lower_corner[y]:
lower_corner[y] = coordinate[y]
city = City(lower_corner, upper_corner, 'unknown')
for subway_entrance in self._subway_entrances:
city.add_city_object(subway_entrance)
return city

View File

@ -9,10 +9,11 @@ import geopandas
from hub.city_model_structure.city import City from hub.city_model_structure.city import City
from hub.imports.geometry.citygml import CityGml from hub.imports.geometry.citygml import CityGml
from hub.imports.geometry.obj import Obj from hub.imports.geometry.obj import Obj
from hub.imports.geometry.osm_subway import OsmSubway
from hub.imports.geometry.rhino import Rhino from hub.imports.geometry.rhino import Rhino
from hub.imports.geometry.gpandas import GPandas from hub.imports.geometry.gpandas import GPandas
from hub.imports.geometry.geojson import Geojson from hub.imports.geometry.geojson import Geojson
from hub.helpers.utils import validate_import_export_type
from hub.hub_logger import logger
class GeometryFactory: class GeometryFactory:
@ -24,13 +25,20 @@ class GeometryFactory:
data_frame=None, data_frame=None,
height_field=None, height_field=None,
year_of_construction_field=None, year_of_construction_field=None,
function_field=None): function_field=None,
function_to_hub=None):
self._file_type = '_' + file_type.lower() self._file_type = '_' + file_type.lower()
class_funcs = validate_import_export_type(GeometryFactory)
if self._file_type not in class_funcs:
err_msg = f"Wrong import type. Valid functions include {class_funcs}"
logger.error(err_msg)
raise Exception(err_msg)
self._path = path self._path = path
self._data_frame = data_frame self._data_frame = data_frame
self._height_field = height_field self._height_field = height_field
self._year_of_construction_field = year_of_construction_field self._year_of_construction_field = year_of_construction_field
self._function_field = function_field self._function_field = function_field
self._function_to_hub = function_to_hub
@property @property
def _citygml(self) -> City: def _citygml(self) -> City:
@ -38,7 +46,11 @@ class GeometryFactory:
Enrich the city by using CityGML information as data source Enrich the city by using CityGML information as data source
:return: City :return: City
""" """
return CityGml(self._path, self._height_field, self._year_of_construction_field, self._function_field).city return CityGml(self._path,
self._height_field,
self._year_of_construction_field,
self._function_field,
self._function_to_hub).city
@property @property
def _obj(self) -> City: def _obj(self) -> City:
@ -64,15 +76,11 @@ class GeometryFactory:
Enrich the city by using Geojson information as data source Enrich the city by using Geojson information as data source
:return: City :return: City
""" """
return Geojson(self._path, self._height_field, self._year_of_construction_field, self._function_field).city return Geojson(self._path,
self._height_field,
@property self._year_of_construction_field,
def _osm_subway(self) -> City: self._function_field,
""" self._function_to_hub).city
Enrich the city by using OpenStreetMap information as data source
:return: City
"""
return OsmSubway(self._path).city
@property @property
def _rhino(self) -> City: def _rhino(self) -> City:

View File

@ -8,6 +8,7 @@ import xmltodict
from pathlib import Path from pathlib import Path
from hub.city_model_structure.machine import Machine from hub.city_model_structure.machine import Machine
class LcaMachine: class LcaMachine:
def __init__(self, city, base_path): def __init__(self, city, base_path):
self._city = city self._city = city
@ -22,6 +23,8 @@ class LcaMachine:
self._lca = xmltodict.parse(xml.read()) self._lca = xmltodict.parse(xml.read())
for machine in self._lca["library"]["machines"]['machine']: for machine in self._lca["library"]["machines"]['machine']:
self._city.machines.append(Machine(machine['@id'], machine['@name'], machine['work_efficiency']['#text'], self._city.machines.append(Machine(machine['@id'], machine['@name'], machine['work_efficiency']['#text'],
machine['work_efficiency']['@unit'], machine['energy_consumption_rate']['#text'], machine['work_efficiency']['@unit'],
machine['energy_consumption_rate']['@unit'], machine['carbon_emission_factor']['#text'], machine['energy_consumption_rate']['#text'],
machine['carbon_emission_factor']['@unit'])) machine['energy_consumption_rate']['@unit'],
machine['carbon_emission_factor']['#text'],
machine['carbon_emission_factor']['@unit']))

Some files were not shown because too many files have changed in this diff Show More