Merge branch 'main' into hp_results

This commit is contained in:
Peter Yefi 2023-03-20 16:55:45 -04:00
commit ff55b502a6
69 changed files with 2214 additions and 1546 deletions

View File

@ -8,12 +8,13 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
class Catalog: class Catalog:
""" """
Catalogs base class not implemented instance of the Catalog base class, catalog_factories will inherit from this class. Catalogs base class not implemented instance of the Catalog base class,
catalog_factories will inherit from this class.
""" """
def names(self, category=None): def names(self, category=None):
""" """
Base property to return the catalog entries names Base property to return the catalog entries names.
:return: Catalog names filter by category if provided :return: Catalog names filter by category if provided
""" """
raise NotImplementedError raise NotImplementedError

View File

@ -1,21 +1,21 @@
""" """
Cost catalog Cost catalog
SPDX - License - Identifier: LGPL - 3.0 - or -later SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group Copyright © 2023 Concordia CERC group
Project Coder Atiya atiya.atiya@mail.concordia.ca Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
import xmltodict import xmltodict
from hub.catalog_factories.catalog import Catalog 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.archetype import Archetype
from hub.catalog_factories.data_models.cost.content import Content from hub.catalog_factories.data_models.cost.content import Content
from hub.catalog_factories.data_models.cost.capital_cost import CapitalCost
from hub.catalog_factories.data_models.cost.chapter import Chapter
from hub.catalog_factories.data_models.cost.item_description import ItemDescription
from hub.catalog_factories.data_models.cost.operational_cost import OperationalCost
from hub.catalog_factories.data_models.cost.fuel import Fuel
from hub.catalog_factories.data_models.cost.income import Income
from hub.catalog_factories.data_models.cost.cost_helper import CostHelper
class MontrealCustomCatalog(Catalog): class MontrealCustomCatalog(Catalog):
@ -28,90 +28,93 @@ class MontrealCustomCatalog(Catalog):
self._content = Content(self._load_archetypes()) self._content = Content(self._load_archetypes())
@staticmethod @staticmethod
def _get_threesome(entry): def _item_with_threesome(entry, item_type):
_reposition = float(entry['reposition']['#text']) _reposition = float(entry[item_type]['reposition']['#text'])
_investment = float(entry['initial_investment']['#text']) _reposition_unit = entry[item_type]['reposition']['@cost_unit']
_lifetime = float(entry['lifetime_equipment']['#text']) _investment = float(entry[item_type]['investment_cost']['#text'])
return _reposition, _investment, _lifetime _investment_unit = entry[item_type]['investment_cost']['@cost_unit']
_lifetime = float(entry[item_type]['lifetime_equipment']['#text'])
_item_description = ItemDescription(item_type,
initial_investment=_investment,
initial_investment_unit=_investment_unit,
reposition=_reposition,
reposition_unit=_reposition_unit,
lifetime=_lifetime)
return _item_description
@staticmethod
def _item_with_refurbishment_values(entry, item_type):
_refurbishment = float(entry[item_type]['refurbishment_cost']['#text'])
_refurbishment_unit = entry[item_type]['refurbishment_cost']['@cost_unit']
_item_description = ItemDescription(item_type,
refurbishment=_refurbishment,
refurbishment_unit=_refurbishment_unit)
return _item_description
def _get_capital_costs(self, entry): def _get_capital_costs(self, entry):
structural = float(entry['structural']['#text']) general_chapters = []
sub_structural = float(entry['sub_structural']['#text']) chapters_titles = CostHelper().chapters_in_lod1
surface_finish = float(entry['surface_finish']['#text']) items_list = []
engineer = float(entry['engineer']['#text']) item_type = 'B10_superstructure'
opaque_reposition, opaque_initial_investment, opaque_lifetime = \ item_description = self._item_with_refurbishment_values(entry, item_type)
self._get_threesome(entry['envelope']['opaque']) items_list.append(item_description)
transparent_reposition, transparent_initial_investment, transparent_lifetime = \ for item in entry['B20_envelope']:
self._get_threesome(entry['envelope']['transparent']) item_type = item
envelope = Envelope(opaque_reposition, item_description = self._item_with_refurbishment_values(entry['B20_envelope'], item_type)
opaque_initial_investment, items_list.append(item_description)
opaque_lifetime, item_type = 'B30_roofing'
transparent_reposition, item_description = self._item_with_refurbishment_values(entry, item_type)
transparent_initial_investment, items_list.append(item_description)
transparent_lifetime) general_chapters.append(Chapter('B_shell', items_list))
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 = \ items_list = []
self._get_threesome(entry['systems']['photovoltaic_system']) item_type = 'D301010_photovoltaic_system'
other_conditioning_systems_reposition, other_conditioning_systems_initial_investment, \ item_description = self._item_with_threesome(entry['D30_hvac']['D3010_energy_supply'], item_type)
other_conditioning_systems_lifetime = self._get_threesome(entry['systems']['other_systems']) items_list.append(item_description)
lighting_reposition, lighting_initial_investment, lighting_lifetime = \ item_type_list = ['D3020_heat_generating_systems', 'D3030_cooling_generation_systems', 'D3040_distribution_systems',
self._get_threesome(entry['systems']['lighting']) 'D3080_other_hvac_ahu']
systems = Systems(hvac, for item_type in item_type_list:
photovoltaic_system_reposition, item_description = self._item_with_threesome(entry['D30_hvac'], item_type)
photovoltaic_system_initial_investment, items_list.append(item_description)
photovoltaic_system_lifetime, item_type = 'D5020lighting_and_branch_wiring'
other_conditioning_systems_reposition, item_description = self._item_with_threesome(entry['D50_electrical'], item_type)
other_conditioning_systems_initial_investment, items_list.append(item_description)
other_conditioning_systems_lifetime, general_chapters.append(Chapter('D_services', items_list))
lighting_reposition,
lighting_initial_investment, design_allowance = float(entry['Z_allowances_overhead_profit']['Z10_design_allowance']['#text']) / 100
lighting_lifetime) overhead_and_profit = float(entry['Z_allowances_overhead_profit']['Z10_overhead_and_profit']['#text']) / 100
_capital_cost = CapitalCost(structural, _capital_cost = CapitalCost(general_chapters, design_allowance, overhead_and_profit)
sub_structural,
envelope,
systems,
surface_finish,
engineer)
return _capital_cost return _capital_cost
@staticmethod @staticmethod
def _get_operational_costs(entry): def _get_operational_costs(entry):
fuel_type = entry['fuel']['@fuel_type'] fuels = []
fuel_fixed_operational_monthly = float(entry['fuel']['fixed']['fixed_monthly']['#text']) for item in entry['fuels']:
fuel_fixed_operational_peak = float(entry['fuel']['fixed']['fixed_power']['#text']) / 1000 fuel_type = item['fuel']['@fuel_type']
fuel_variable_operational = float(entry['fuel']['variable']['#text']) / 1000 / 3600 fuel_variable = float(entry['fuel']['variable']['#text'])
fuel_variable_units = float(entry['fuel']['variable']['@cost_unit'])
fuel_fixed_monthly = None
fuel_fixed_peak = None
if fuel_type == 'electricity':
fuel_fixed_monthly = float(entry['fuel']['fixed']['fixed_monthly']['#text'])
fuel_fixed_peak = float(entry['fuel']['fixed']['fixed_power']['#text']) / 1000
elif fuel_type == 'gas':
fuel_fixed_monthly = float(entry['fuel']['fixed']['fixed_monthly']['#text'])
fuel = Fuel(fuel_type,
fixed_monthly=fuel_fixed_monthly,
fixed_power=fuel_fixed_peak,
variable=fuel_variable,
variable_units=fuel_variable_units)
fuels.append(fuel)
heating_equipment_maintenance = float(entry['maintenance']['heating_equipment']['#text']) / 1000 heating_equipment_maintenance = float(entry['maintenance']['heating_equipment']['#text']) / 1000
cooling_equipment_maintenance = float(entry['maintenance']['cooling_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']) 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']) co2_emissions = float(entry['CO2_cost']['#text'])
_operational_cost = OperationalCost(fuel_type, _operational_cost = OperationalCost(fuels,
fuel_fixed_operational_monthly,
fuel_fixed_operational_peak,
fuel_variable_operational,
heating_equipment_maintenance, heating_equipment_maintenance,
cooling_equipment_maintenance, cooling_equipment_maintenance,
general_hvac_equipment_maintenance,
photovoltaic_system_maintenance, photovoltaic_system_maintenance,
other_systems_maintenance,
co2_emissions) co2_emissions)
return _operational_cost return _operational_cost
@ -121,7 +124,10 @@ class MontrealCustomCatalog(Catalog):
for archetype in archetypes: for archetype in archetypes:
function = archetype['@function'] function = archetype['@function']
municipality = archetype['@municipality'] municipality = archetype['@municipality']
currency = archetype['@currency'] country = archetype['@country']
lod = float(archetype['@lod'])
currency = archetype['currency']
print(currency)
capital_cost = self._get_capital_costs(archetype['capital_cost']) capital_cost = self._get_capital_costs(archetype['capital_cost'])
operational_cost = self._get_operational_costs(archetype['operational_cost']) operational_cost = self._get_operational_costs(archetype['operational_cost'])
end_of_life_cost = float(archetype['end_of_life_cost']['#text']) end_of_life_cost = float(archetype['end_of_life_cost']['#text'])
@ -129,17 +135,21 @@ class MontrealCustomCatalog(Catalog):
hvac = float(archetype['incomes']['subsidies']['hvac_subsidy']['#text']) hvac = float(archetype['incomes']['subsidies']['hvac_subsidy']['#text'])
photovoltaic_system = float(archetype['incomes']['subsidies']['photovoltaic_subsidy']['#text']) photovoltaic_system = float(archetype['incomes']['subsidies']['photovoltaic_subsidy']['#text'])
electricity_exports = float(archetype['incomes']['energy_exports']['electricity']['#text']) / 1000 / 3600 electricity_exports = float(archetype['incomes']['energy_exports']['electricity']['#text']) / 1000 / 3600
heat_exports = float(archetype['incomes']['energy_exports']['heat']['#text']) / 1000 / 3600 reduction_tax = float(archetype['incomes']['tax_reduction']['#text']) / 100
co2 = float(archetype['incomes']['CO2_income']['#text']) income = Income(construction_subsidy=construction,
income = Income(construction, hvac, photovoltaic_system, electricity_exports, heat_exports, co2) hvac_subsidy=hvac,
_catalog_archetypes.append(Archetype(function, photovoltaic_subsidy=photovoltaic_system,
electricity_export=electricity_exports,
reductions_tax=reduction_tax)
_catalog_archetypes.append(Archetype(lod,
function,
municipality, municipality,
country,
currency, currency,
capital_cost, capital_cost,
operational_cost, operational_cost,
end_of_life_cost, end_of_life_cost,
income)) income))
return _catalog_archetypes return _catalog_archetypes
def names(self, category=None): def names(self, category=None):

View File

@ -1,8 +1,8 @@
""" """
Archetype catalog Cost Archetype catalog Cost
SPDX - License - Identifier: LGPL - 3.0 - or -later SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group Copyright © 2023 Concordia CERC group
Project Coder Atiya atiya.atiya@mail.concordia.ca Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
from hub.catalog_factories.data_models.cost.capital_cost import CapitalCost from hub.catalog_factories.data_models.cost.capital_cost import CapitalCost
@ -11,9 +11,21 @@ from hub.catalog_factories.data_models.cost.income import Income
class Archetype: class Archetype:
def __init__(self, function, municipality, currency, capital_cost, operational_cost, end_of_life_cost, income): def __init__(self,
lod,
function,
municipality,
country,
currency,
capital_cost,
operational_cost,
end_of_life_cost,
income):
self._lod = lod
self._function = function self._function = function
self._municipality = municipality self._municipality = municipality
self._country = country
self._currency = currency self._currency = currency
self._capital_cost = capital_cost self._capital_cost = capital_cost
self._operational_cost = operational_cost self._operational_cost = operational_cost
@ -26,7 +38,15 @@ class Archetype:
Get name Get name
:return: string :return: string
""" """
return f'{self._municipality}_{self._function}' return f'{self._country}_{self._municipality}_{self._function}_{self._lod}'
@property
def lod(self):
"""
Get level of detail of the catalog
:return: string
"""
return self._lod
@property @property
def function(self): def function(self):
@ -44,6 +64,14 @@ class Archetype:
""" """
return self._municipality return self._municipality
@property
def country(self):
"""
Get country
:return: string
"""
return self._country
@property @property
def currency(self): def currency(self):
""" """

View File

@ -1,68 +1,40 @@
""" """
Cost catalog CapitalCost Capital costs included in the catalog
SPDX - License - Identifier: LGPL - 3.0 - or -later SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group Copyright © 2023 Concordia CERC group
Project Coder Atiya atiya.atiya@mail.concordia.ca Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
from hub.catalog_factories.data_models.cost.envelope import Envelope from typing import List
from hub.catalog_factories.data_models.cost.systems import Systems from hub.catalog_factories.data_models.cost.chapter import Chapter
class CapitalCost: class CapitalCost:
def __init__(self, structural, sub_structural, envelope, systems, surface_finish, engineer): def __init__(self, general_chapters, design_allowance, overhead_and_profit):
self._structural = structural self._general_chapters = general_chapters
self._sub_structural = sub_structural self._design_allowance = design_allowance
self._envelope = envelope self._overhead_and_profit = overhead_and_profit
self._systems = systems
self._surface_finish = surface_finish
self._engineer = engineer
@property @property
def structural(self): def general_chapters(self) -> List[Chapter]:
""" """
Get structural cost per building volume in currency/m3 Get general chapters in capital costs
:return: [Chapter]
"""
return self._general_chapters
@property
def design_allowance(self):
"""
Get design allowance in percentage (-)
:return: float :return: float
""" """
return self._structural return self._design_allowance
@property @property
def sub_structural(self): def overhead_and_profit(self):
""" """
Get sub structural cost per building foot-print in currency/m2 Get overhead profit in percentage (-)
:return: float :return: float
""" """
return self._sub_structural return self._overhead_and_profit
@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,32 @@
"""
Cost chapter description
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from typing import List
from hub.catalog_factories.data_models.cost.item_description import ItemDescription
class Chapter:
def __init__(self, chapter_type, items):
self._chapter_type = chapter_type
self._items = items
@property
def chapter_type(self):
"""
Get chapter type
:return: str
"""
return self._chapter_type
@property
def items(self) -> List[ItemDescription]:
"""
Get list of items contained in the chapter
:return: [str]
"""
return self._items

View File

@ -0,0 +1,48 @@
"""
Cost helper
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import hub.helpers.constants as cte
from typing import Dict
class CostHelper:
"""
Cost helper class
"""
_costs_units = {
'currency/m2': cte.CURRENCY_PER_SQM,
'currency/m3': cte.CURRENCY_PER_CBM,
'currency/kW': cte.CURRENCY_PER_KW,
'currency/kWh': cte.CURRENCY_PER_KWH,
'currency/month': cte.CURRENCY_PER_MONTH,
'currency/l': cte.CURRENCY_PER_LITRE,
'currency/kg': cte.CURRENCY_PER_KG,
'currency/(m3/h)': cte.CURRENCY_PER_CBM_PER_HOUR,
'%': cte.PERCENTAGE
}
_chapters_in_lod1 = {
'B_shell': cte.SUPERSTRUCTURE,
'D_services': cte.ENVELOPE,
'Z_allowances_overhead_profit': cte.ALLOWANCES_OVERHEAD_PROFIT
}
@property
def costs_units(self) -> Dict:
"""
List of supported costs units
:return: dict
"""
return self._costs_units
@property
def chapters_in_lod1(self) -> Dict:
"""
List of chapters included in lod 1
:return: dict
"""
return self._chapters_in_lod1

View File

@ -1,66 +0,0 @@
"""
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,54 @@
"""
Cost fuel
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from typing import Union
class Fuel:
def __init__(self, fuel_type,
fixed_monthly=None,
fixed_power=None,
variable=None,
variable_units=None):
self._fuel_type = fuel_type
self._fixed_monthly = fixed_monthly
self._fixed_power = fixed_power
self._variable = variable
self._variable_units = variable_units
@property
def type(self):
"""
Get fuel type
:return: str
"""
return self._fuel_type
@property
def fixed_monthly(self) -> Union[None, float]:
"""
Get fixed operational costs in currency per month
:return: None or float
"""
return self._fixed_monthly
@property
def fixed_power(self) -> Union[None, float]:
"""
Get fixed operational costs depending on the peak power consumed in currency per month per kW
:return: None or float
"""
return self._fixed_power
@property
def variable(self) -> Union[tuple[None, None], tuple[float, str]]:
"""
Get variable costs in given units
:return: None, None or float, str
"""
return self._variable, self._variable_units

View File

@ -1,96 +0,0 @@
"""
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

@ -1,64 +1,62 @@
""" """
Income from costs catalog Incomes included in the costs catalog
SPDX - License - Identifier: LGPL - 3.0 - or -later SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Álvarez de Uribarri pilar.monsalvete@concordia.ca Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
from typing import Union
class Income: class Income:
def __init__(self, construction, hvac, photovoltaic_system, electricity_exports, heat_exports, co2): def __init__(self, construction_subsidy=None,
self._construction = construction hvac_subsidy=None,
self._hvac = hvac photovoltaic_subsidy=None,
self._photovoltaic_system = photovoltaic_system electricity_export=None,
self._electricity_exports = electricity_exports reductions_tax=None):
self._heat_exports = heat_exports
self._co2 = co2 self._construction_subsidy = construction_subsidy
self._hvac_subsidy = hvac_subsidy
self._photovoltaic_subsidy = photovoltaic_subsidy
self._electricity_export = electricity_export
self._reductions_tax = reductions_tax
@property @property
def construction(self): def construction_subsidy(self) -> Union[None, float]:
""" """
Get construction subsidy in % of total investment construction cost Get subsidy for construction in percentage
:return: float :return: None or float
""" """
return self._construction return self._construction_subsidy
@property @property
def hvac(self): def hvac_subsidy(self) -> Union[None, float]:
""" """
Get hvac subsidy in % of total investment HVAC cost Get subsidy for HVAC system in percentage
:return: float :return: None or float
""" """
return self._hvac return self._hvac_subsidy
@property @property
def photovoltaic_system(self): def photovoltaic_subsidy(self) -> Union[None, float]:
""" """
Get photovoltaic system subsidy in % of total investment photovoltaic cost Get subsidy PV systems in percentage
:return: float :return: None or float
""" """
return self._photovoltaic_system return self._photovoltaic_subsidy
@property @property
def electricity_exports(self): def electricity_export(self) -> Union[None, float]:
""" """
Get electricity exports gains in currency/J Get electricity export incomes in currency per J
:return: float :return: None or float
""" """
return self._construction return self._construction_subsidy
@property @property
def heat_exports(self): def reductions_tax(self) -> Union[None, float]:
""" """
Get heat exports gains in currency/J Get reduction in taxes in percentage (-)
:return: float :return: None or float
""" """
return self._heat_exports return self._reductions_tax
@property
def co2(self):
"""
Get co2 income in currency/kg
:return: float
"""
return self._co2

View File

@ -0,0 +1,68 @@
"""
Cost item properties
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from typing import Union
class ItemDescription:
def __init__(self, item_type,
initial_investment=None,
initial_investment_unit=None,
refurbishment=None,
refurbishment_unit=None,
reposition=None,
reposition_unit=None,
lifetime=None):
self._item_type = item_type
self._initial_investment = initial_investment
self._initial_investment_unit = initial_investment_unit
self._refurbishment = refurbishment
self._refurbishment_unit = refurbishment_unit
self._reposition = reposition
self._reposition_unit = reposition_unit
self._lifetime = lifetime
@property
def type(self):
"""
Get item type
:return: str
"""
return self._item_type
@property
def initial_investment(self) -> Union[tuple[None, None], tuple[float, str]]:
"""
Get initial investment of the specific item in given units
:return: None, None or float, str
"""
return self._initial_investment, self._initial_investment_unit
@property
def refurbishment(self) -> Union[tuple[None, None], tuple[float, str]]:
"""
Get refurbishment costs of the specific item in given units
:return: None, None or float, str
"""
return self._refurbishment, self._refurbishment_unit
@property
def reposition(self) -> Union[tuple[None, None], tuple[float, str]]:
"""
Get reposition costs of the specific item in given units
:return: None, None or float, str
"""
return self._reposition, self._reposition_unit
@property
def lifetime(self) -> Union[None, float]:
"""
Get lifetime in years
:return: None or float
"""
return self._lifetime

View File

@ -1,104 +1,58 @@
""" """
Cost catalog OperationalCost Operational costs included in the catalog
SPDX - License - Identifier: LGPL - 3.0 - or -later SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group Copyright © 2023 Concordia CERC group
Project Coder Atiya atiya.atiya@mail.concordia.ca Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
from typing import List
from hub.catalog_factories.data_models.cost.fuel import Fuel
class OperationalCost: class OperationalCost:
def __init__(self, fuel_type, fuel_fixed_operational_monthly, fuel_fixed_operational_peak, def __init__(self, fuels, maintenance_heating, maintenance_cooling, maintenance_pv, co2):
fuel_variable_operational, heating_equipment_maintenance, cooling_equipment_maintenance, self._fuels = fuels
general_hvac_equipment_maintenance, photovoltaic_system_maintenance, other_systems_maintenance, self._maintenance_heating = maintenance_heating
co2_emissions): self._maintenance_cooling = maintenance_cooling
self._fuel_type = fuel_type self._maintenance_pv = maintenance_pv
self._fuel_fixed_operational_monthly = fuel_fixed_operational_monthly self._co2 = co2
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 @property
def fuel_type(self): def fuels(self) -> List[Fuel]:
""" """
Get fuel type Get fuels listed in capital costs
:return: string :return: [FUEL]
""" """
return self._fuel_type return self._fuels
@property @property
def fuel_fixed_operational_monthly(self): def maintenance_heating(self):
""" """
Get fuel fixed operational cost in currency/month Get cost of maintaining the heating system in currency/W
:return: float :return: float
""" """
return self._fuel_fixed_operational_monthly return self._maintenance_heating
@property @property
def fuel_fixed_operational_peak(self): def maintenance_cooling(self):
""" """
Get fuel fixed operational cost per peak power in currency/W Get cost of maintaining the cooling system in currency/W
:return: float :return: float
""" """
return self._fuel_fixed_operational_peak return self._maintenance_cooling
@property @property
def fuel_variable_operational(self): def maintenance_pv(self):
""" """
Get fuel variable operational cost in currency/J Get cost of maintaining the PV system in currency/m2
:return: float :return: float
""" """
return self._fuel_variable_operational return self._maintenance_pv
@property @property
def heating_equipment_maintenance(self): def co2(self):
""" """
Get heating equipment maintenance cost per peak power in currency/W Get cost of CO2 emissions in currency/kgCO2
:return: float :return: float
""" """
return self._heating_equipment_maintenance return self._co2
@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

@ -1,106 +0,0 @@
"""
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

@ -0,0 +1,54 @@
"""
Usage catalog domestic hot water
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Álvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from typing import Union, List
from hub.catalog_factories.data_models.usages.schedule import Schedule
class DomesticHotWater:
"""
DomesticHotWater class
"""
def __init__(self, density, peak_flow, service_temperature, schedules):
self._density = density
self._peak_flow = peak_flow
self._service_temperature = service_temperature
self._schedules = schedules
@property
def density(self) -> Union[None, float]:
"""
Get domestic hot water load density in Watts per m2
:return: None or float
"""
return self._density
@property
def peak_flow(self) -> Union[None, float]:
"""
Get domestic hot water peak_flow density in m3 per second and m2
:return: None or float
"""
return self._peak_flow
@property
def service_temperature(self) -> Union[None, float]:
"""
Get service temperature in degrees Celsius
:return: None or float
"""
return self._service_temperature
@property
def schedules(self) -> Union[None, List[Schedule]]:
"""
Get schedules
dataType = fraction of loads
:return: None or [Schedule]
"""
return self._schedules

View File

@ -10,6 +10,7 @@ from hub.catalog_factories.data_models.usages.appliances import Appliances
from hub.catalog_factories.data_models.usages.lighting import Lighting from hub.catalog_factories.data_models.usages.lighting import Lighting
from hub.catalog_factories.data_models.usages.ocupancy import Occupancy from hub.catalog_factories.data_models.usages.ocupancy import Occupancy
from hub.catalog_factories.data_models.usages.thermal_control import ThermalControl from hub.catalog_factories.data_models.usages.thermal_control import ThermalControl
from hub.catalog_factories.data_models.usages.domestic_hot_water import DomesticHotWater
class Usage: class Usage:
@ -21,7 +22,8 @@ class Usage:
occupancy, occupancy,
lighting, lighting,
appliances, appliances,
thermal_control): thermal_control,
domestic_hot_water):
self._name = name self._name = name
self._hours_day = hours_day self._hours_day = hours_day
self._days_year = days_year self._days_year = days_year
@ -32,6 +34,7 @@ class Usage:
self._lighting = lighting self._lighting = lighting
self._appliances = appliances self._appliances = appliances
self._thermal_control = thermal_control self._thermal_control = thermal_control
self._domestic_hot_water = domestic_hot_water
@property @property
def name(self) -> Union[None, str]: def name(self) -> Union[None, str]:
@ -108,7 +111,15 @@ class Usage:
@property @property
def thermal_control(self) -> Union[None, ThermalControl]: def thermal_control(self) -> Union[None, ThermalControl]:
""" """
Get thermal control of this thermal zone Get thermal control information
:return: None or ThermalControl :return: None or ThermalControl
""" """
return self._thermal_control return self._thermal_control
@property
def domestic_hot_water(self) -> Union[None, DomesticHotWater]:
"""
Get domestic hot water information
:return: None or DomesticHotWater
"""
return self._domestic_hot_water

View File

@ -0,0 +1,189 @@
"""
NRCAN energy systems catalog
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import json
import urllib.request
import xmltodict
import hub.helpers.constants as cte
from hub.catalog_factories.catalog import Catalog
from hub.catalog_factories.data_models.usages.appliances import Appliances
from hub.catalog_factories.data_models.usages.content import Content
from hub.catalog_factories.data_models.usages.lighting import Lighting
from hub.catalog_factories.data_models.usages.ocupancy import Occupancy
from hub.catalog_factories.data_models.usages.schedule import Schedule
from hub.catalog_factories.data_models.usages.thermal_control import ThermalControl
from hub.catalog_factories.data_models.usages.usage import Usage
from hub.catalog_factories.usage.usage_helper import UsageHelper
class NrcanCatalog(Catalog):
def __init__(self, path):
path = str(path / 'nrcan.xml')
self._content = None
self._schedules = {}
with open(path) as xml:
self._metadata = xmltodict.parse(xml.read())
self._base_url = self._metadata['nrcan']['@base_url']
self._load_schedules()
self._content = Content(self._load_archetypes())
def _load_archetypes(self):
usages = []
name = self._metadata['nrcan']
url = f'{self._base_url}{name["space_types_location"]}'
with urllib.request.urlopen(url) as json_file:
space_types = json.load(json_file)['tables']['space_types']['table']
# space_types = [st for st in space_types if st['building_type'] == 'Space Function']
space_types = [st for st in space_types if st['space_type'] == 'WholeBuilding']
for space_type in space_types:
# usage_type = space_type['space_type']
usage_type = space_type['building_type']
occupancy_schedule_name = space_type['occupancy_schedule']
lighting_schedule_name = space_type['lighting_schedule']
appliance_schedule_name = space_type['electric_equipment_schedule']
hvac_schedule_name = space_type['exhaust_schedule']
if 'FAN' in hvac_schedule_name:
hvac_schedule_name = hvac_schedule_name.replace('FAN', 'Fan')
heating_setpoint_schedule_name = space_type['heating_setpoint_schedule']
cooling_setpoint_schedule_name = space_type['cooling_setpoint_schedule']
occupancy_schedule = self._get_schedules(occupancy_schedule_name)
lighting_schedule = self._get_schedules(lighting_schedule_name)
appliance_schedule = self._get_schedules(appliance_schedule_name)
heating_schedule = self._get_schedules(heating_setpoint_schedule_name)
cooling_schedule = self._get_schedules(cooling_setpoint_schedule_name)
hvac_availability = self._get_schedules(hvac_schedule_name)
occupancy_density = space_type['occupancy_per_area']
# ACH
mechanical_air_change = space_type['ventilation_air_changes']
# cfm/ft2 to m3/m2.s
ventilation_rate = space_type['ventilation_per_area'] / (cte.METERS_TO_FEET * cte.MINUTES_TO_SECONDS)
if ventilation_rate == 0:
# cfm/person to m3/m2.s
ventilation_rate = space_type['ventilation_per_person'] / occupancy_density\
/ (cte.METERS_TO_FEET * cte.MINUTES_TO_SECONDS)
# W/sqft to W/m2
lighting_density = space_type['lighting_per_area'] * cte.METERS_TO_FEET * cte.METERS_TO_FEET
lighting_radiative_fraction = space_type['lighting_fraction_radiant']
lighting_convective_fraction = 0
if lighting_radiative_fraction is not None:
lighting_convective_fraction = 1 - lighting_radiative_fraction
lighting_latent_fraction = 0
# W/sqft to W/m2
appliances_density = space_type['electric_equipment_per_area'] * cte.METERS_TO_FEET * cte.METERS_TO_FEET
appliances_radiative_fraction = space_type['electric_equipment_fraction_radiant']
appliances_latent_fraction = space_type['electric_equipment_fraction_latent']
appliances_convective_fraction = 0
if appliances_radiative_fraction is not None and appliances_latent_fraction is not None:
appliances_convective_fraction = 1 - appliances_radiative_fraction - appliances_latent_fraction
occupancy = Occupancy(occupancy_density,
None,
None,
None,
occupancy_schedule)
lighting = Lighting(lighting_density,
lighting_convective_fraction,
lighting_radiative_fraction,
lighting_latent_fraction,
lighting_schedule)
appliances = Appliances(appliances_density,
appliances_convective_fraction,
appliances_radiative_fraction,
appliances_latent_fraction,
appliance_schedule)
thermal_control = ThermalControl(None,
None,
None,
hvac_availability,
heating_schedule,
cooling_schedule)
hours_day = None
days_year = None
usages.append(Usage(usage_type,
hours_day,
days_year,
mechanical_air_change,
ventilation_rate,
occupancy,
lighting,
appliances,
thermal_control))
return usages
def names(self, category=None):
"""
Get the catalog elements names
:parm: optional category filter
"""
if category is None:
_names = {'archetypes': [], 'constructions': [], 'materials': [], 'windows': []}
for archetype in self._content.archetypes:
_names['archetypes'].append(archetype.name)
for construction in self._content.constructions:
_names['constructions'].append(construction.name)
for material in self._content.materials:
_names['materials'].append(material.name)
for window in self._content.windows:
_names['windows'].append(window.name)
else:
_names = {category: []}
if category.lower() == 'archetypes':
for archetype in self._content.archetypes:
_names[category].append(archetype.name)
elif category.lower() == 'constructions':
for construction in self._content.constructions:
_names[category].append(construction.name)
elif category.lower() == 'materials':
for material in self._content.materials:
_names[category].append(material.name)
elif category.lower() == 'windows':
for window in self._content.windows:
_names[category].append(window.name)
else:
raise ValueError(f'Unknown category [{category}]')
def entries(self, category=None):
"""
Get the catalog elements
:parm: optional category filter
"""
if category is None:
return self._content
else:
if category.lower() == 'archetypes':
return self._content.archetypes
elif category.lower() == 'constructions':
return self._content.constructions
elif category.lower() == 'materials':
return self._content.materials
elif category.lower() == 'windows':
return self._content.windows
else:
raise ValueError(f'Unknown category [{category}]')
def get_entry(self, name):
"""
Get one catalog element by names
:parm: entry name
"""
for entry in self._content.archetypes:
if entry.name.lower() == name.lower():
return entry
for entry in self._content.constructions:
if entry.name.lower() == name.lower():
return entry
for entry in self._content.materials:
if entry.name.lower() == name.lower():
return entry
for entry in self._content.windows:
if entry.name.lower() == name.lower():
return entry
raise IndexError(f"{name} doesn't exists in the catalog")

View File

@ -0,0 +1,42 @@
"""
Usage catalog factory, publish the usage information
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Álvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from pathlib import Path
from typing import TypeVar
from hub.catalog_factories.energy_systems.nrcan_catalog import NrcanCatalog
from hub.hub_logger import logger
from hub.helpers.utils import validate_import_export_type
Catalog = TypeVar('Catalog')
class UsageCatalogFactory:
def __init__(self, file_type, base_path=None):
if base_path is None:
base_path = Path(Path(__file__).parent.parent / 'data/energy_systems')
self._catalog_type = '_' + file_type.lower()
class_funcs = validate_import_export_type(UsageCatalogFactory)
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
@property
def _nrcan(self):
"""
Retrieve NRCAN catalog
"""
# nrcan retrieves the data directly from github
return NrcanCatalog(self._path)
@property
def catalog(self) -> Catalog:
"""
Enrich the city given to the class using the class given handler
:return: Catalog
"""
return getattr(self, self._catalog_type, lambda: None)

View File

@ -14,6 +14,7 @@ from hub.catalog_factories.data_models.usages.appliances import Appliances
from hub.catalog_factories.data_models.usages.content import Content from hub.catalog_factories.data_models.usages.content import Content
from hub.catalog_factories.data_models.usages.lighting import Lighting from hub.catalog_factories.data_models.usages.lighting import Lighting
from hub.catalog_factories.data_models.usages.ocupancy import Occupancy from hub.catalog_factories.data_models.usages.ocupancy import Occupancy
from hub.catalog_factories.data_models.usages.domestic_hot_water import DomesticHotWater
from hub.catalog_factories.data_models.usages.schedule import Schedule from hub.catalog_factories.data_models.usages.schedule import Schedule
from hub.catalog_factories.data_models.usages.thermal_control import ThermalControl from hub.catalog_factories.data_models.usages.thermal_control import ThermalControl
from hub.catalog_factories.data_models.usages.usage import Usage from hub.catalog_factories.data_models.usages.usage import Usage
@ -51,6 +52,7 @@ class ComnetCatalog(Catalog):
ventilation_rate = self._archetypes['ventilation rate'][comnet_usage] ventilation_rate = self._archetypes['ventilation rate'][comnet_usage]
# convert cfm/ft2 to m3/m2.s # convert cfm/ft2 to m3/m2.s
ventilation_rate = ventilation_rate / (cte.METERS_TO_FEET * cte.MINUTES_TO_SECONDS) ventilation_rate = ventilation_rate / (cte.METERS_TO_FEET * cte.MINUTES_TO_SECONDS)
domestic_hot_water_archetype = self._archetypes['water heating'][comnet_usage]
# get occupancy # get occupancy
occupancy_density = occupancy_archetype[0] / pow(cte.METERS_TO_FEET, 2) occupancy_density = occupancy_archetype[0] / pow(cte.METERS_TO_FEET, 2)
@ -96,6 +98,16 @@ class ComnetCatalog(Catalog):
self._schedules[schedule_name]['ClgSetPt'] self._schedules[schedule_name]['ClgSetPt']
) )
# get domestic hot water
density = domestic_hot_water_archetype
# convert Btu/h/occ to W/m2
density = float(density) * cte.BTU_H_TO_WATTS * occupancy_density
domestic_hot_water_service_temperature = self._schedules[schedule_name]['WtrHtrSetPt'][0].values[0]
domestic_hot_water = DomesticHotWater(density,
None,
domestic_hot_water_service_temperature,
self._schedules[schedule_name]['Service Hot Water']
)
usages.append(Usage(comnet_usage, usages.append(Usage(comnet_usage,
hours_day, hours_day,
days_year, days_year,
@ -104,7 +116,8 @@ class ComnetCatalog(Catalog):
occupancy, occupancy,
lighting, lighting,
appliances, appliances,
thermal_control)) thermal_control,
domestic_hot_water))
self._content = Content(usages) self._content = Content(usages)
@ -136,7 +149,7 @@ class ComnetCatalog(Catalog):
_schedule_values[day] = _extracted_data.iloc[start:end, 3:27].to_numpy().tolist()[0] _schedule_values[day] = _extracted_data.iloc[start:end, 3:27].to_numpy().tolist()[0]
_schedule = [] _schedule = []
for day in _schedule_values: for day in _schedule_values:
if schedule_name == 'ClgSetPt' or schedule_name == 'HtgSetPt': if schedule_name == 'ClgSetPt' or schedule_name == 'HtgSetPt' or schedule_name == 'WtrHtrSetPt':
# to celsius # to celsius
if 'n.a.' in _schedule_values[day]: if 'n.a.' in _schedule_values[day]:
_schedule_values[day] = None _schedule_values[day] = None

View File

@ -16,6 +16,7 @@ from hub.catalog_factories.data_models.usages.appliances import Appliances
from hub.catalog_factories.data_models.usages.content import Content from hub.catalog_factories.data_models.usages.content import Content
from hub.catalog_factories.data_models.usages.lighting import Lighting from hub.catalog_factories.data_models.usages.lighting import Lighting
from hub.catalog_factories.data_models.usages.ocupancy import Occupancy from hub.catalog_factories.data_models.usages.ocupancy import Occupancy
from hub.catalog_factories.data_models.usages.domestic_hot_water import DomesticHotWater
from hub.catalog_factories.data_models.usages.schedule import Schedule from hub.catalog_factories.data_models.usages.schedule import Schedule
from hub.catalog_factories.data_models.usages.thermal_control import ThermalControl from hub.catalog_factories.data_models.usages.thermal_control import ThermalControl
from hub.catalog_factories.data_models.usages.usage import Usage from hub.catalog_factories.data_models.usages.usage import Usage
@ -36,7 +37,7 @@ class NrcanCatalog(Catalog):
@staticmethod @staticmethod
def _extract_schedule(raw): def _extract_schedule(raw):
nrcan_schedule_type = raw['category'] nrcan_schedule_type = raw['category']
if 'Heating' in raw['name']: if 'Heating' in raw['name'] and 'Water' not in raw['name']:
nrcan_schedule_type = f'{nrcan_schedule_type} Heating' nrcan_schedule_type = f'{nrcan_schedule_type} Heating'
elif 'Cooling' in raw['name']: elif 'Cooling' in raw['name']:
nrcan_schedule_type = f'{nrcan_schedule_type} Cooling' nrcan_schedule_type = f'{nrcan_schedule_type} Cooling'
@ -45,8 +46,8 @@ class NrcanCatalog(Catalog):
hub_type = UsageHelper().nrcan_schedule_type_to_hub_schedule_type[nrcan_schedule_type] hub_type = UsageHelper().nrcan_schedule_type_to_hub_schedule_type[nrcan_schedule_type]
data_type = UsageHelper().nrcan_data_type_to_hub_data_type[raw['units']] data_type = UsageHelper().nrcan_data_type_to_hub_data_type[raw['units']]
time_step = UsageHelper().nrcan_time_to_hub_time[raw['type']] time_step = UsageHelper().nrcan_time_to_hub_time[raw['type']]
# nrcan only uses yearly range for the schedules # nrcan only uses daily range for the schedules
time_range = cte.YEAR time_range = cte.DAY
day_types = UsageHelper().nrcan_day_type_to_hub_days[raw['day_types']] day_types = UsageHelper().nrcan_day_type_to_hub_days[raw['day_types']]
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)
@ -78,10 +79,8 @@ class NrcanCatalog(Catalog):
url = f'{self._base_url}{name["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['space_type'] == 'WholeBuilding'] 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['building_type'] usage_type = space_type['building_type']
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']
@ -91,12 +90,14 @@ class NrcanCatalog(Catalog):
hvac_schedule_name = hvac_schedule_name.replace('FAN', 'Fan') 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']
domestic_hot_water_schedule_name = space_type['service_water_heating_schedule']
occupancy_schedule = self._get_schedules(occupancy_schedule_name) occupancy_schedule = self._get_schedules(occupancy_schedule_name)
lighting_schedule = self._get_schedules(lighting_schedule_name) lighting_schedule = self._get_schedules(lighting_schedule_name)
appliance_schedule = self._get_schedules(appliance_schedule_name) appliance_schedule = self._get_schedules(appliance_schedule_name)
heating_schedule = self._get_schedules(heating_setpoint_schedule_name) heating_schedule = self._get_schedules(heating_setpoint_schedule_name)
cooling_schedule = self._get_schedules(cooling_setpoint_schedule_name) cooling_schedule = self._get_schedules(cooling_setpoint_schedule_name)
hvac_availability = self._get_schedules(hvac_schedule_name) hvac_availability = self._get_schedules(hvac_schedule_name)
domestic_hot_water_load_schedule = self._get_schedules(domestic_hot_water_schedule_name)
occupancy_density = space_type['occupancy_per_area'] occupancy_density = space_type['occupancy_per_area']
@ -124,6 +125,11 @@ class NrcanCatalog(Catalog):
if appliances_radiative_fraction is not None and appliances_latent_fraction is not None: if appliances_radiative_fraction is not None and appliances_latent_fraction is not None:
appliances_convective_fraction = 1 - appliances_radiative_fraction - appliances_latent_fraction appliances_convective_fraction = 1 - appliances_radiative_fraction - appliances_latent_fraction
# peak flow in gallons/h/ft2
domestic_hot_water_peak_flow = space_type['service_water_heating_peak_flow_per_area'] \
* cte.GALLONS_TO_QUBIC_METERS / cte.HOUR_TO_SECONDS * pow(cte.METERS_TO_FEET, 2)
domestic_hot_water_service_temperature = space_type['service_water_heating_target_temperature']
occupancy = Occupancy(occupancy_density, occupancy = Occupancy(occupancy_density,
None, None,
None, None,
@ -145,6 +151,11 @@ class NrcanCatalog(Catalog):
hvac_availability, hvac_availability,
heating_schedule, heating_schedule,
cooling_schedule) cooling_schedule)
domestic_hot_water = DomesticHotWater(None,
domestic_hot_water_peak_flow,
domestic_hot_water_service_temperature,
domestic_hot_water_load_schedule)
hours_day = None hours_day = None
days_year = None days_year = None
usages.append(Usage(usage_type, usages.append(Usage(usage_type,
@ -155,7 +166,8 @@ class NrcanCatalog(Catalog):
occupancy, occupancy,
lighting, lighting,
appliances, appliances,
thermal_control)) thermal_control,
domestic_hot_water))
return usages return usages
def names(self, category=None): def names(self, category=None):

View File

@ -19,7 +19,8 @@ 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 'Fan': cte.HVAC_AVAILABILITY,
'Service Water Heating': cte.DOMESTIC_HOT_WATER
} }
_nrcan_data_type_to_hub_data_type = { _nrcan_data_type_to_hub_data_type = {
'FRACTION': cte.FRACTION, 'FRACTION': cte.FRACTION,

View File

@ -152,6 +152,10 @@ class Polygon:
self._area += np.linalg.norm(np.cross(ab, ac)) / 2 self._area += np.linalg.norm(np.cross(ab, ac)) / 2
return self._area return self._area
@area.setter
def area(self, value):
self._area = value
@property @property
def normal(self) -> np.ndarray: def normal(self) -> np.ndarray:
""" """

View File

@ -38,6 +38,7 @@ class Building(CityObject):
self._shell = None self._shell = None
self._alias = None self._alias = None
self._type = 'building' self._type = 'building'
self._cold_water_temperature = dict()
self._heating = dict() self._heating = dict()
self._cooling = dict() self._cooling = dict()
self._lighting_electrical_demand = dict() self._lighting_electrical_demand = dict()
@ -265,6 +266,22 @@ class Building(CityObject):
if value is not None: if value is not None:
self._storeys_above_ground = int(value) self._storeys_above_ground = int(value)
@property
def cold_water_temperature(self) -> {float}:
"""
Get cold water temperature in degrees Celsius
:return: dict{DataFrame(float)}
"""
return self._cold_water_temperature
@cold_water_temperature.setter
def cold_water_temperature(self, value):
"""
Set cold water temperature in degrees Celsius
:param value: dict{DataFrame(float)}
"""
self._cold_water_temperature = value
@property @property
def heating(self) -> dict: def heating(self) -> dict:
""" """

View File

@ -0,0 +1,87 @@
"""
Domestic Hot Water module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from typing import Union, List
from hub.city_model_structure.attributes.schedule import Schedule
class DomesticHotWater:
"""
DomesticHotWater class
"""
def __init__(self):
self._density = None
self._peak_flow = None
self._service_temperature = None
self._schedules = None
@property
def density(self) -> Union[None, float]:
"""
Get domestic hot water load density in Watts per m2
:return: None or float
"""
return self._density
@density.setter
def density(self, value):
"""
Set domestic hot water load density in Watts per m2
:param value: float
"""
if value is not None:
self._density = float(value)
@property
def peak_flow(self) -> Union[None, float]:
"""
Get domestic hot water peak_flow density in m3 per second and m2
:return: None or float
"""
return self._peak_flow
@peak_flow.setter
def peak_flow(self, value):
"""
Set domestic hot water peak_flow density in m3 per second and m2
:return: None or float
"""
self._peak_flow = value
@property
def service_temperature(self) -> Union[None, float]:
"""
Get service temperature in degrees Celsius
:return: None or float
"""
return self._service_temperature
@service_temperature.setter
def service_temperature(self, value):
"""
Set service temperature in degrees Celsius
:param value: float
"""
if value is not None:
self._service_temperature = float(value)
@property
def schedules(self) -> Union[None, List[Schedule]]:
"""
Get schedules
dataType = fraction
:return: None or [Schedule]
"""
return self._schedules
@schedules.setter
def schedules(self, value):
"""
Set schedules
dataType = fraction
:param value: [Schedule]
"""
self._schedules = value

View File

@ -15,6 +15,7 @@ from hub.city_model_structure.building_demand.appliances import Appliances
from hub.city_model_structure.building_demand.lighting import Lighting from hub.city_model_structure.building_demand.lighting import Lighting
from hub.city_model_structure.building_demand.internal_gain import InternalGain from hub.city_model_structure.building_demand.internal_gain import InternalGain
from hub.city_model_structure.building_demand.thermal_control import ThermalControl from hub.city_model_structure.building_demand.thermal_control import ThermalControl
from hub.city_model_structure.building_demand.domestic_hot_water import DomesticHotWater
from hub.city_model_structure.attributes.schedule import Schedule from hub.city_model_structure.attributes.schedule import Schedule
import hub.helpers.constants as cte import hub.helpers.constants as cte
@ -53,6 +54,7 @@ class ThermalZone:
self._appliances = None self._appliances = None
self._internal_gains = None self._internal_gains = None
self._thermal_control = None self._thermal_control = None
self._domestic_hot_water = None
self._usages = None self._usages = None
@property @property
@ -590,6 +592,46 @@ class ThermalZone:
return self._thermal_control return self._thermal_control
@property
def domestic_hot_water(self) -> Union[None, DomesticHotWater]:
"""
Get domestic hot water information of this thermal zone
:return: None or DomesticHotWater
"""
self._domestic_hot_water = DomesticHotWater()
_mean_peak_density_load = 0
_mean_peak_flow = 0
_mean_service_temperature = 0
for usage in self.usages:
_mean_peak_density_load += usage.percentage * usage.domestic_hot_water.density
_mean_peak_flow += usage.percentage * usage.domestic_hot_water.peak_flow
_mean_service_temperature += usage.percentage * usage.domestic_hot_water.service_temperature
self._domestic_hot_water.density = _mean_peak_density_load
self._domestic_hot_water.peak_flow = _mean_peak_flow
self._domestic_hot_water.service_temperature = _mean_service_temperature
_domestic_hot_water_reference = self.usages[0].domestic_hot_water
if _domestic_hot_water_reference.schedules is not None:
_schedules = []
for i_schedule in range(0, len(_domestic_hot_water_reference.schedules)):
schedule = Schedule()
schedule.type = _domestic_hot_water_reference.schedules[i_schedule].type
schedule.day_types = _domestic_hot_water_reference.schedules[i_schedule].day_types
schedule.data_type = _domestic_hot_water_reference.schedules[i_schedule].data_type
schedule.time_step = _domestic_hot_water_reference.schedules[i_schedule].time_step
schedule.time_range = _domestic_hot_water_reference.schedules[i_schedule].time_range
new_values = []
for i_value in range(0, len(_domestic_hot_water_reference.schedules[i_schedule].values)):
_new_value = 0
for usage in self.usages:
_new_value += usage.percentage * usage.domestic_hot_water.schedules[i_schedule].values[i_value]
new_values.append(_new_value)
schedule.values = new_values
_schedules.append(schedule)
self._domestic_hot_water.schedules = _schedules
return self._domestic_hot_water
@property @property
def total_floor_area(self): def total_floor_area(self):
""" """

View File

@ -12,6 +12,7 @@ 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.lighting import Lighting
from hub.city_model_structure.building_demand.appliances import Appliances 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.thermal_control import ThermalControl
from hub.city_model_structure.building_demand.domestic_hot_water import DomesticHotWater
from hub.city_model_structure.building_demand.internal_gain import InternalGain from hub.city_model_structure.building_demand.internal_gain import InternalGain
@ -31,6 +32,7 @@ class Usage:
self._lighting = None self._lighting = None
self._appliances = None self._appliances = None
self._thermal_control = None self._thermal_control = None
self._domestic_hot_water = None
@property @property
def id(self): def id(self):
@ -236,7 +238,7 @@ class Usage:
@property @property
def thermal_control(self) -> Union[None, ThermalControl]: def thermal_control(self) -> Union[None, ThermalControl]:
""" """
Get thermal control of this thermal zone Get thermal control information
:return: None or ThermalControl :return: None or ThermalControl
""" """
return self._thermal_control return self._thermal_control
@ -244,7 +246,23 @@ class Usage:
@thermal_control.setter @thermal_control.setter
def thermal_control(self, value): def thermal_control(self, value):
""" """
Set thermal control for this thermal zone Set thermal control information
:param value: ThermalControl :param value: ThermalControl
""" """
self._thermal_control = value self._thermal_control = value
@property
def domestic_hot_water(self) -> Union[None, DomesticHotWater]:
"""
Get domestic hot water information
:return: None or ThermalControl
"""
return self._domestic_hot_water
@domestic_hot_water.setter
def domestic_hot_water(self, value):
"""
Set domestic hot water information
:return: None or ThermalControl
"""
self._domestic_hot_water = value

View File

@ -1,250 +0,0 @@
"""
UsageZone 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 UsageZone:
"""
UsageZone class
"""
def __init__(self):
self._id = None
self._usage = 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 usage(self) -> Union[None, str]:
"""
Get usage zone usage
:return: None or str
"""
return self._usage
@usage.setter
def usage(self, value):
"""
Set usage zone usage
:param value: str
"""
if value is not None:
self._usage = 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 = 0
_internal_gain.radiative_fraction = 0
_internal_gain.convective_fraction = 0
if _total_heat_gain != 0:
_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

@ -459,6 +459,7 @@ class City:
for surface in city_object.surfaces: for surface in city_object.surfaces:
radiation = surface.global_irradiance radiation = surface.global_irradiance
if 'year' not in radiation and 'month' not in radiation: if 'year' not in radiation and 'month' not in radiation:
continue continue
elif "year" in radiation: elif "year" in radiation:
building_radiation += radiation["year"].iloc[0] building_radiation += radiation["year"].iloc[0]
@ -468,11 +469,11 @@ class City:
if building_radiation < min_radiation: if building_radiation < min_radiation:
min_radiation = building_radiation min_radiation = building_radiation
selected_city_object = city_object selected_city_object = city_object
# merge the city object with the minimum radiation # merge the city object with the minimum radiation
if selected_city_object is not None: if selected_city_object is not None:
_merge_city.add_city_object(selected_city_object) _merge_city.add_city_object(selected_city_object)
else: else:
_merge_city.add_city_object(building) _merge_city.add_city_object(building)
return _merge_city return _merge_city
@property @property

View File

@ -34,7 +34,9 @@ class CityObject:
self._max_y = ConfigurationHelper().min_coordinate self._max_y = ConfigurationHelper().min_coordinate
self._max_z = ConfigurationHelper().min_coordinate self._max_z = ConfigurationHelper().min_coordinate
self._centroid = None self._centroid = None
self._volume = None
self._external_temperature = dict() self._external_temperature = dict()
self._ground_temperature = dict()
self._global_horizontal = dict() self._global_horizontal = dict()
self._diffuse = dict() self._diffuse = dict()
self._beam = dict() self._beam = dict()
@ -63,7 +65,13 @@ class CityObject:
Get city object volume in cubic meters Get city object volume in cubic meters
:return: float :return: float
""" """
return self.simplified_polyhedron.volume if self._volume is None:
self._volume = self.simplified_polyhedron.volume
return self._volume
@volume.setter
def volume(self, value):
self._volume = value
@property @property
def detailed_polyhedron(self) -> Polyhedron: def detailed_polyhedron(self) -> Polyhedron:
@ -158,6 +166,24 @@ class CityObject:
""" """
self._external_temperature = value self._external_temperature = value
# todo: this is the new format we will use to get rid of the data frames
@property
def ground_temperature(self) -> dict:
"""
Get ground temperature under the city object in Celsius at different depths in meters for different time steps
example of use: {month: {0.5: [10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10]}}
:return: dict{dict{[float]}}
"""
return self._ground_temperature
@ground_temperature.setter
def ground_temperature(self, value):
"""
Set ground temperature under the city object in Celsius at different depths
:param value: dict{dict{[float]}}
"""
self._ground_temperature = value
@property @property
def global_horizontal(self) -> dict: def global_horizontal(self) -> dict:
""" """

View File

@ -1,6 +1,5 @@
# These values are intended as configurable assumptions # These values are intended as configurable assumptions
[buildings] [buildings]
max_location_distance_for_shared_walls = 5.0
min_coordinate = -1.7976931348623157e+308 min_coordinate = -1.7976931348623157e+308
max_coordinate = 1.7976931348623157e+308 max_coordinate = 1.7976931348623157e+308
comnet_lighting_latent = 0 comnet_lighting_latent = 0
@ -18,3 +17,7 @@ convective_heat_transfer_coefficient_exterior = 20
soil_conductivity = 3 soil_conductivity = 3
#m #m
soil_thickness = 0.5 soil_thickness = 0.5
short_wave_reflectance = 0.3
#C
cold_water_temperature = 10

View File

@ -1,89 +1,204 @@
<archetypes> <archetypes>
<archetype function="residential" municipality="montreal" currency="CAD"> <archetype function="residential" municipality="montreal" country="CA" lod="1">
<currency>CAD</currency>
<capital_cost> <capital_cost>
<structural cost_unit="currency/m3"> 56 </structural> <B_shell>
<sub_structural cost_unit="currency/m2"> 9.8 </sub_structural> <B10_superstructure>
<envelope> <refurbishment_cost_basement cost_unit="currency/m2"> 0 </refurbishment_cost_basement>
<opaque> </B10_superstructure>
<reposition cost_unit="currency/m2"> 43.4 </reposition> <B20_envelope>
<initial_investment cost_unit="currency/m2"> 36 </initial_investment> <B2010_opaque_walls>
<lifetime_equipment lifetime="years"> 50 </lifetime_equipment> <refurbishment_cost cost_unit="currency/m2"> 304 </refurbishment_cost>
</opaque> </B2010_opaque_walls>
<transparent> <B2020_transparent>
<reposition cost_unit="currency/m2"> 78 </reposition> <refurbishment_cost cost_unit="currency/m2"> 857.14 </refurbishment_cost>
<initial_investment cost_unit="currency/m2"> 984.5 </initial_investment> </B2020_transparent>
<lifetime_equipment lifetime="years"> 20 </lifetime_equipment> </B20_envelope>
</transparent> <B30_roofing>
</envelope> <B3010_opaque_roof>
<systems> <refurbishment_cost cost_unit="currency/m2"> 118 </refurbishment_cost>
<hvac> </B3010_opaque_roof>
<heating_equipment_cost> </B30_roofing>
<initial_investment cost_unit="currency/kW"> 363.5 </initial_investment> </B_shell>
<reposition cost_unit="currency/kW"> 363.5 </reposition> <D_services>
<D30_hvac>
<D3010_energy_supply>
<D301010_photovoltaic_system>
<initial_investment cost_unit="currency/m2"> 800 </initial_investment>
<reposition cost_unit="currency/m2"> 800 </reposition>
<lifetime_equipment lifetime="years"> 25 </lifetime_equipment>
</D301010_photovoltaic_system>
</D3010_energy_supply>
<D3020_heat_generating_systems>
<investment_cost cost_unit="currency/kW"> 622.86 </investment_cost>
<reposition cost_unit="currency/kW"> 622.86 </reposition>
<lifetime_equipment lifetime="years"> 25 </lifetime_equipment>
</D3020_heat_generating_systems>
<D3030_cooling_generation_systems>
<investment_cost cost_unit="currency/kW"> 622.86 </investment_cost>
<reposition cost_unit="currency/kW"> 622.86 </reposition>
<lifetime_equipment lifetime="years"> 15 </lifetime_equipment> <lifetime_equipment lifetime="years"> 15 </lifetime_equipment>
</heating_equipment_cost> </D3030_cooling_generation_systems>
<cooling_equipment_cost> <D3040_distribution_systems>
<initial_investment cost_unit="currency/kW"> 363.5 </initial_investment> <investment_cost cost_unit="currency/kW"> 0 </investment_cost>
<reposition cost_unit="currency/kW"> 363.5 </reposition> <reposition cost_unit="currency/kW"> 0 </reposition>
<lifetime_equipment lifetime="years"> 15 </lifetime_equipment> <lifetime_equipment lifetime="years"> 15 </lifetime_equipment>
</cooling_equipment_cost> </D3040_distribution_systems>
<general_hvac_equipment_cost> <D3080_other_hvac_ahu>
<initial_investment cost_unit="currency/(m3/h)"> 363.5 </initial_investment> <investment_cost cost_unit="currency/kW"> 47.62 </investment_cost>
<reposition cost_unit="currency/(m3/h)"> 363.5 </reposition> <reposition cost_unit="currency/kW"> 47.62 </reposition>
<lifetime_equipment lifetime="years"> 15 </lifetime_equipment> <lifetime_equipment lifetime="years"> 15 </lifetime_equipment>
</general_hvac_equipment_cost> </D3080_other_hvac_ahu>
</hvac> </D30_hvac>
<photovoltaic_system> <D50_electrical>
<initial_investment cost_unit="currency/m2"> 17 </initial_investment> <D5020lighting_and_branch_wiring>
<reposition cost_unit="currency/m2"> 17 </reposition> <refurbishment_cost cost_unit="currency/kW"> 139 </refurbishment_cost>
<lifetime_equipment lifetime="years"> 15 </lifetime_equipment> <reposition cost_unit="currency/kW"> 139 </reposition>
</photovoltaic_system> <lifetime_equipment lifetime="years"> 20 </lifetime_equipment>
<other_systems> </D5020lighting_and_branch_wiring>
<initial_investment cost_unit="currency/m2"> 365 </initial_investment> </D50_electrical>
<reposition cost_unit="currency/m2"> 365 </reposition> </D_services>
<lifetime_equipment lifetime="years"> 15 </lifetime_equipment> <Z_allowances_overhead_profit>
</other_systems> <Z10_design_allowance cost_unit="%"> 2.5 </Z10_design_allowance>
<lighting> <Z10_overhead_and_profit cost_unit="%"> 14 </Z10_overhead_and_profit>
<initial_investment cost_unit="currency/m2"> 365 </initial_investment> </Z_allowances_overhead_profit>
<reposition cost_unit="currency/m2"> 365 </reposition> </capital_cost>
<lifetime_equipment lifetime="years"> 15 </lifetime_equipment> <operational_cost>
</lighting> <fuels>
</systems> <fuel fuel_type="electricity">
<surface_finish cost_unit="currency/m2"> 88 </surface_finish> <fixed_monthly cost_unit="currency/month"> 12.27 </fixed_monthly>
<engineer cost_unit="%"> 2.5 </engineer> <fixed_power cost_unit="currency/month*kW"> 0 </fixed_power>
<variable cost_unit="currency/kWh"> 0.075 </variable>
</fuel>
<fuel fuel_type="gas">
<fixed_monthly cost_unit="currency/month"> 17.71 </fixed_monthly>
<variable cost_unit="currency/kWh"> 0.640 </variable>
</fuel>
<fuel fuel_type="diesel">
<variable cost_unit="currency/l"> 1.2 </variable>
</fuel>
<fuel fuel_type="biomass">
<variable cost_unit="currency/kg"> 0.09 </variable>
</fuel>
</fuels>
<maintenances>
<maintenance type="heating_equipment" cost_unit="currency/kW">40</maintenance>
<maintenance type="cooling_equipment" cost_unit="currency/kW">40</maintenance>
<maintenance type="photovoltaic_system" cost_unit="currency/m2">1</maintenance>
</maintenances>
<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>
<subsidy type="construction" cost_unit="%">2</subsidy>
<subsidy type="hvac" cost_unit="%">1.5</subsidy>
<subsidy type="photovoltaic" cost_unit="%">3.6</subsidy>
</subsidies>
<energy_exports>
<energy_export type="electricity" cost_unit="currency/kWh">0</energy_export>
</energy_exports>
<tax_reduction cost_unit="%">2</tax_reduction>
</incomes>
</archetype>
<archetype function="non-residential" municipality="montreal" country="CA" lod="1">
<currency>CAD</currency>
<capital_cost>
<B_shell>
<B10_superstructure>
<refurbishment_cost_basement cost_unit="currency/m2"> 0 </refurbishment_cost_basement>
</B10_superstructure>
<B20_envelope>
<B2010_opaque_walls>
<refurbishment_cost cost_unit="currency/m2"> 304 </refurbishment_cost>
</B2010_opaque_walls>
<B2020_transparent>
<refurbishment_cost cost_unit="currency/m2"> 857.14 </refurbishment_cost>
</B2020_transparent>
</B20_envelope>
<B30_roofing>
<B3010_opaque_roof>
<refurbishment_cost cost_unit="currency/m2"> 118 </refurbishment_cost>
</B3010_opaque_roof>
</B30_roofing>
</B_shell>
<D_services>
<D30_hvac>
<D3010_energy_supply>
<D301010_photovoltaic_system>
<initial_investment cost_unit="currency/m2"> 800 </initial_investment>
<reposition cost_unit="currency/m2"> 800 </reposition>
<lifetime_equipment lifetime="years"> 25 </lifetime_equipment>
</D301010_photovoltaic_system>
</D3010_energy_supply>
<D3020_heat_generating_systems>
<investment_cost cost_unit="currency/kW"> 622.86 </investment_cost>
<reposition cost_unit="currency/kW"> 622.86 </reposition>
<lifetime_equipment lifetime="years"> 25 </lifetime_equipment>
</D3020_heat_generating_systems>
<D3030_cooling_generation_systems>
<investment_cost cost_unit="currency/kW"> 622.86 </investment_cost>
<reposition cost_unit="currency/kW"> 622.86 </reposition>
<lifetime_equipment lifetime="years"> 15 </lifetime_equipment>
</D3030_cooling_generation_systems>
<D3040_distribution_systems>
<refurbishment_cost cost_unit="currency/m2"> 0 </refurbishment_cost>
<reposition cost_unit="currency/kW"> 0 </reposition>
<lifetime_equipment lifetime="years"> 15 </lifetime_equipment>
</D3040_distribution_systems>
<D3080_other_hvac_ahu>
<investment_cost cost_unit="currency/kW"> 47.62 </investment_cost>
<reposition cost_unit="currency/kW"> 47.62 </reposition>
<lifetime_equipment lifetime="years"> 15 </lifetime_equipment>
</D3080_other_hvac_ahu>
</D30_hvac>
<D50_electrical>
<D5020_lighting_and_branch_wiring>
<refurbishment_cost cost_unit="currency/kW"> 139 </refurbishment_cost>
<reposition cost_unit="currency/kW"> 139 </reposition>
<lifetime_equipment lifetime="years"> 20 </lifetime_equipment>
</D5020_lighting_and_branch_wiring>
</D50_electrical>
</D_services>
<Z_allowances_overhead_profit>
<Z10_design_allowance cost_unit="%"> 6 </Z10_design_allowance>
<Z20_overhead_profit cost_unit="%"> 14 </Z20_overhead_profit>
</Z_allowances_overhead_profit>
</capital_cost> </capital_cost>
<operational_cost> <operational_cost>
<fuel fuel_type="electricity"> <fuel fuel_type="electricity">
<fixed> <fixed_monthly cost_unit="currency/month"> 12.27 </fixed_monthly>
<fixed_monthly cost_unit="currency/month"> 0 </fixed_monthly> <fixed_power cost_unit="currency/(month*kW)"> 0 </fixed_power>
<fixed_power cost_unit="currency/kW"> 0 </fixed_power> <variable cost_unit="currency/kWh"> 0.075 </variable>
</fixed>
<variable cost_unit="currency/kWh"> 5.6 </variable>
</fuel> </fuel>
<maintenance> <fuel fuel_type="gas">
<heating_equipment cost_unit="currency/kW"> 40 </heating_equipment> <fixed_monthly cost_unit="currency/month"> 17.71 </fixed_monthly>
<cooling_equipment cost_unit="currency/kW"> 40 </cooling_equipment> <variable cost_unit="currency/m3"> 0.640 </variable>
<general_hvac_equipment cost_unit="currency/(m3/h)"> 0.05 </general_hvac_equipment> </fuel>
<photovoltaic_system cost_unit="currency/m2"> 1 </photovoltaic_system> <fuel fuel_type="diesel">
<other_systems cost_unit="currency/m2"> 4.6 </other_systems> <variable cost_unit="currency/l"> 1.2 </variable>
</maintenance> </fuel>
<fuel fuel_type="biomass">
<variable cost_unit="currency/kg"> 0.09 </variable>
</fuel>
<maintenances>
<maintenance type="heating_equipment" cost_unit="currency/kW">40</maintenance>
<maintenance type="cooling_equipment" cost_unit="currency/kW">40</maintenance>
<maintenance type="photovoltaic_system" cost_unit="currency/m2">1</maintenance>
</maintenances>
<CO2_cost cost_unit="currency/kgCO2"> 30 </CO2_cost> <CO2_cost cost_unit="currency/kgCO2"> 30 </CO2_cost>
</operational_cost> </operational_cost>
<end_of_life_cost cost_unit="currency/m2"> 6.3 </end_of_life_cost> <end_of_life_cost cost_unit="currency/m2"> 6.3 </end_of_life_cost>
<incomes> <incomes>
<subsidies> <subsidies>
<construction_subsidy cost_unit="%"> 2 </construction_subsidy> <subsidy type="construction" cost_unit="%">2</subsidy>
<hvac_subsidy cost_unit="%"> 1.5 </hvac_subsidy> <subsidy type="hvac" cost_unit="%">1.5</subsidy>
<photovoltaic_subsidy cost_unit="%"> 3.6 </photovoltaic_subsidy> <subsidy type="photovoltaic" cost_unit="%">3.6</subsidy>
</subsidies> </subsidies>
<energy_exports> <energy_exports>
<electricity cost_unit="currency/kWh"> 0 </electricity> <energy_export type="electricity" cost_unit="currency/kWh">0</energy_export>
<heat cost_unit="currency/kWh"> 0 </heat>
</energy_exports> </energy_exports>
<tax_reductions> <tax_reduction cost_unit="%">2</tax_reduction>
<reductions_taxes cost_unit="%"> 2 </reductions_taxes>
</tax_reductions>
<CO2_income cost_unit="currency/kgCO2exported"> 0 </CO2_income>
</incomes> </incomes>
</archetype> </archetype>
</archetypes> </archetypes>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<nrcan base_url="https://raw.githubusercontent.com/NREL/openstudio-standards/master/lib/openstudio-standards/standards/necb/ECMS/data/">
<boilers_location>boiler_set.json</boilers_location>
<chillers_location>chiller_set.json</chillers_location>
<curves_location>curves.json</curves_location>
<furnaces_location>furnace_set.json </furnaces_location>
<heat_pumps_location>heat_pumps.json</heat_pumps_location>
<domestic_hot_water_systems_location>shw_set.json</domestic_hot_water_systems_location>
<pvs_location>pv.json</pvs_location>
<air_conditioners_location>unitary_acs.json</air_conditioners_location>
</nrcan>

View File

@ -7,6 +7,8 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
import numpy as np import numpy as np
from pathlib import Path from pathlib import Path
import sys
from hub.hub_logger import logger
from hub.exports.formats.insel import Insel from hub.exports.formats.insel import Insel
from hub.imports.weather.helpers.weather import Weather from hub.imports.weather.helpers.weather import Weather
@ -38,6 +40,10 @@ class InselMonthlyEnergyBalance(Insel):
if building.internal_zones is not None: if building.internal_zones is not None:
for internal_zone in building.internal_zones: for internal_zone in building.internal_zones:
if internal_zone.thermal_zones is None: if internal_zone.thermal_zones is None:
logger.error(f'Building {building.name} has missing values. '
f'Monthly Energy Balance cannot be processed\n')
sys.stderr.write(f'Building {building.name} has missing values. '
f'Monthly Energy Balance cannot be processed\n')
break break
self._contents.append( self._contents.append(
self.generate_meb_template(building, output_path, self._radiation_calculation_method,self._weather_format) self.generate_meb_template(building, output_path, self._radiation_calculation_method,self._weather_format)

View File

@ -4,6 +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
""" """
import json
from typing import Union, Dict
from hub.persistence import City from hub.persistence import City
from hub.persistence import Application from hub.persistence import Application
from hub.persistence import User from hub.persistence import User
@ -23,23 +26,53 @@ class DBFactory:
self._city_object = CityObject(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)
self._simulation_results = SimulationResults(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 application_info(self, application_uuid): def application_info(self, application_uuid) -> Union[Application, None]:
""" """
Retrieve the application info for the given uuid Retrieve the application info for the given uuid
:param application_uuid: the uuid for the application :param application_uuid: the uuid for the application
:return: Application or None
""" """
return self._application.get_by_uuid(application_uuid) return self._application.get_by_uuid(application_uuid)
def user_info(self, name, password, application_id):
"""
Retrieve the user info for the given name and password and application_id
:param name: the user name
:param password: the user password
:param application_id: the application id
:return: User or None
"""
return self._user.get_by_name_application_id_and_password(name, password, application_id)
def user_login(self, name, password, application_uuid): def user_login(self, name, password, application_uuid):
""" """
Retrieve the user info Retrieve the user info
:param name: the user name :param name: the user name
:param password: the user password :param password: the user password
:param application_uuid: the application uuid :param application_uuid: the application uuid
:return: User or None
""" """
return self._user.get_by_name_application_uuid_and_password(name, password, application_uuid) return self._user.get_by_name_application_uuid_and_password(name, password, application_uuid)
def results(self, user_id, application_id, cities, result_names=[]): def cities_by_user_and_application(self, user_id, application_id) -> [City]:
"""
Retrieve the cities belonging to the user and the application
:param user_id: User id
:param application_id: Application id
:return: [City]
"""
return self._city.get_by_user_id_and_application_id(user_id, application_id)
def building_info(self, name, city_id) -> Union[CityObject, None]:
"""
Retrieve the building info
:param name: Building name
:param city_id: City Id
:return: CityObject or None
"""
return self._city_object.get_by_name_and_city(name, city_id)
def results(self, user_id, application_id, cities, result_names=None) -> Dict:
""" """
Retrieve the simulation results for the given cities Retrieve the simulation results for the given cities
:param user_id: the user id owning the results :param user_id: the user id owning the results
@ -47,16 +80,27 @@ class DBFactory:
:param cities: dictionary containing the city and building names for the results :param cities: dictionary containing the city and building names for the results
:param result_names: if given, filter the results to the selected names :param result_names: if given, filter the results to the selected names
""" """
results = [] if result_names is None:
for city in cities['cities'].keys(): result_names = []
city_id = self._city.get_by_user_id_application_id_and_name(user_id, application_id, city).id results = {}
for building_name in cities[city]: for city in cities['cities']:
city_name = next(iter(city))
result_set = self._city.get_by_user_id_application_id_and_name(user_id, application_id, city_name)
if result_set is None:
continue
city_id = result_set.id
results[city_name] = []
for building_name in city[city_name]:
if self._city_object.get_by_name_and_city(building_name, city_id) is None:
continue
city_object_id = self._city_object.get_by_name_and_city(building_name, city_id).id city_object_id = self._city_object.get_by_name_and_city(building_name, city_id).id
results.append(self._simulation_results.get_simulation_results_by_city_id_city_object_id_and_names( _ = self._simulation_results.get_simulation_results_by_city_id_city_object_id_and_names(
city_id, city_id,
city_object_id, city_object_id,
result_names)) result_names)
for value in _:
values = json.loads(value.values)
values["building"] = building_name
results[city_name].append(values)
return results return results

View File

@ -71,7 +71,7 @@ class ExportsFactory:
Export the city geometry to obj with grounded coordinates Export the city geometry to obj with grounded coordinates
:return: None :return: None
""" """
return Obj(self._city, self._path).to_ground_points() return Obj(self._city, self._path)
@property @property
def _sra(self): def _sra(self):

View File

@ -11,24 +11,51 @@ from hub.exports.formats.triangular import Triangular
from hub.imports.geometry_factory import GeometryFactory from hub.imports.geometry_factory import GeometryFactory
class Obj(Triangular): class Obj:
""" """
Export to obj format Export to obj format
""" """
def __init__(self, city, path): def __init__(self, city, path):
super().__init__(city, path, 'obj') self._city = city
self._path = path
self._export()
def _to_vertex(self, coordinate):
x = coordinate[0] - self._city.lower_corner[0]
y = coordinate[1] - self._city.lower_corner[1]
z = coordinate[2] - self._city.lower_corner[2]
return f'v {x} {y} {z}\n'
def _export(self):
if self._city.name is None:
self._city.name = 'unknown_city'
file_name = self._city.name + '.obj'
file_path = (Path(self._path).resolve() / file_name).resolve()
vertices = {}
with open(file_path, 'w') as obj:
obj.write("# cerc-hub export\n")
vertex_index = 0
faces = []
for building in self._city.buildings:
obj.write(f'# building {building.name}\n')
for surface in building.surfaces:
obj.write(f'# surface {surface.name}\n')
face = 'f '
for coordinate in surface.perimeter_polygon.coordinates:
vertex = self._to_vertex(coordinate)
if vertex not in vertices.keys():
vertex_index += 1
vertices[vertex] = vertex_index
current = vertex_index
obj.write(vertex)
else:
current = vertices[vertex]
face = f'{face} {current}'
faces.append(f'{face} {face.split(" ")[1]}\n')
obj.writelines(faces)
faces = []
def to_ground_points(self):
"""
Move closer to the origin
"""
file_name_in = self._city.name + '.' + 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_out = (Path(self._path).resolve() / file_name_out).resolve()
obj = GeometryFactory('obj', path=file_path_in)
scene = obj.scene
scene.rezero()
obj_file = trimesh.exchange.obj.export_obj(scene)
with open(file_path_out, 'w') as file:
file.write(obj_file)

View File

@ -8,6 +8,7 @@ import xmltodict
from hub.imports.weather_factory import WeatherFactory from hub.imports.weather_factory import WeatherFactory
import hub.helpers.constants as cte import hub.helpers.constants as cte
from hub.helpers.configuration_helper import ConfigurationHelper
class SimplifiedRadiosityAlgorithm: class SimplifiedRadiosityAlgorithm:
@ -88,10 +89,15 @@ class SimplifiedRadiosityAlgorithm:
'@Simulate': f'{simulate}' '@Simulate': f'{simulate}'
} }
walls, roofs, floors = [], [], [] walls, roofs, floors = [], [], []
default_short_wave_reflectance = ConfigurationHelper().short_wave_reflectance
for surface in building.surfaces: for surface in building.surfaces:
if surface.short_wave_reflectance is None:
short_wave_reflectance = default_short_wave_reflectance
else:
short_wave_reflectance = surface.short_wave_reflectance
surface_dict = { surface_dict = {
'@id': f'{surface.id}', '@id': f'{surface.id}',
'@ShortWaveReflectance': f'{surface.short_wave_reflectance}' '@ShortWaveReflectance': f'{short_wave_reflectance}'
} }
for point_index, point in enumerate(surface.perimeter_polygon.coordinates): for point_index, point in enumerate(surface.perimeter_polygon.coordinates):
point = self._correct_point(point) point = self._correct_point(point)

View File

@ -17,14 +17,6 @@ class ConfigurationHelper:
self._config = configparser.ConfigParser() self._config = configparser.ConfigParser()
self._config.read(config_file) self._config.read(config_file)
@property
def max_location_distance_for_shared_walls(self) -> float:
"""
Get configured maximal distance between attributes to consider that they may share walls in meters
:return: 5.0
"""
return self._config.getfloat('buildings', 'max_location_distance_for_shared_walls')
@property @property
def min_coordinate(self) -> float: def min_coordinate(self) -> float:
""" """
@ -138,3 +130,19 @@ class ConfigurationHelper:
:return: 0.5 :return: 0.5
""" """
return self._config.getfloat('buildings', 'soil_thickness').real return self._config.getfloat('buildings', 'soil_thickness').real
@property
def short_wave_reflectance(self) -> float:
"""
Get configured short wave reflectance for surfaces that don't have construction assigned
:return: 0.3
"""
return self._config.getfloat('buildings', 'short_wave_reflectance').real
@property
def cold_water_temperature(self) -> float:
"""
Get configured cold water temperature in Celsius
:return: 10
"""
return self._config.getfloat('buildings', 'cold_water_temperature').real

View File

@ -8,13 +8,17 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
# universal constants # universal constants
KELVIN = 273.15 KELVIN = 273.15
WATER_DENSITY = 1000
WATER_HEAT_CAPACITY = 4182
# converters # converters
HOUR_TO_MINUTES = 60 HOUR_TO_MINUTES = 60
MINUTES_TO_SECONDS = 60 MINUTES_TO_SECONDS = 60
HOUR_TO_SECONDS = 3600
METERS_TO_FEET = 3.28084 METERS_TO_FEET = 3.28084
BTU_H_TO_WATTS = 0.29307107 BTU_H_TO_WATTS = 0.29307107
KILO_WATTS_HOUR_TO_JULES = 3600000 KILO_WATTS_HOUR_TO_JULES = 3600000
GALLONS_TO_QUBIC_METERS = 0.0037854117954011185
# time # time
SECOND = 'second' SECOND = 'second'
@ -137,6 +141,7 @@ HEATING_SET_POINT = 'HtgSetPt'
EQUIPMENT = 'Equipment' EQUIPMENT = 'Equipment'
ACTIVITY = 'Activity' ACTIVITY = 'Activity'
PEOPLE_ACTIVITY_LEVEL = 'People Activity Level' PEOPLE_ACTIVITY_LEVEL = 'People Activity Level'
DOMESTIC_HOT_WATER = 'Domestic Hot Water'
# Geometry # Geometry
EPSILON = 0.0000001 EPSILON = 0.0000001
@ -157,3 +162,19 @@ MIN_FLOAT = float('-inf')
# Tools # Tools
SRA = 'sra' SRA = 'sra'
INSEL_MEB = 'insel meb' INSEL_MEB = 'insel meb'
# Costs units
CURRENCY_PER_SQM = 'currency/m2'
CURRENCY_PER_CBM = 'currency/m3'
CURRENCY_PER_KW = 'currency/kW'
CURRENCY_PER_KWH = 'currency/kWh'
CURRENCY_PER_MONTH = 'currency/month'
CURRENCY_PER_LITRE = 'currency/l'
CURRENCY_PER_KG = 'currency/kg'
CURRENCY_PER_CBM_PER_HOUR = 'currency/(m3/h)'
PERCENTAGE = '%'
# Costs chapters
SUPERSTRUCTURE = 'B_shell'
ENVELOPE = 'D_services'
ALLOWANCES_OVERHEAD_PROFIT = 'Z_allowances_overhead_profit'

View File

@ -8,6 +8,7 @@ Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
import hub.helpers.constants as cte import hub.helpers.constants as cte
class AlkisFunctionToHubFunction: class AlkisFunctionToHubFunction:
def __init__(self): def __init__(self):

View File

@ -12,21 +12,21 @@ class HftFunctionToHubFunction:
def __init__(self): def __init__(self):
self._dictionary = { self._dictionary = {
'residential': cte.RESIDENTIAL, 'residential': cte.RESIDENTIAL,
'single family house': cte.SINGLE_FAMILY_HOUSE, 'single family house': cte.SINGLE_FAMILY_HOUSE,
'multifamily house': cte.MULTI_FAMILY_HOUSE, 'multifamily house': cte.MULTI_FAMILY_HOUSE,
'hotel': cte.HOTEL, 'hotel': cte.HOTEL,
'hospital': cte.HOSPITAL, 'hospital': cte.HOSPITAL,
'outpatient': cte.OUT_PATIENT_HEALTH_CARE, 'outpatient': cte.OUT_PATIENT_HEALTH_CARE,
'commercial': cte.SUPERMARKET, 'commercial': cte.SUPERMARKET,
'strip mall': cte.STRIP_MALL, 'strip mall': cte.STRIP_MALL,
'warehouse': cte.WAREHOUSE, 'warehouse': cte.WAREHOUSE,
'primary school': cte.PRIMARY_SCHOOL, 'primary school': cte.PRIMARY_SCHOOL,
'secondary school': cte.EDUCATION, 'secondary school': cte.EDUCATION,
'office': cte.MEDIUM_OFFICE, 'office': cte.MEDIUM_OFFICE,
'large office': cte.LARGE_OFFICE 'large office': cte.LARGE_OFFICE
} }
@property @property
def dictionary(self) -> dict: def dictionary(self) -> dict:
return self._dictionary return self._dictionary

View File

@ -12,66 +12,66 @@ class HubFunctionToNrcanConstructionFunction:
def __init__(self): def __init__(self):
self._dictionary = { self._dictionary = {
cte.RESIDENTIAL: 'MidriseApartment', cte.RESIDENTIAL: 'MidriseApartment',
cte.SINGLE_FAMILY_HOUSE: 'MidriseApartment', cte.SINGLE_FAMILY_HOUSE: 'MidriseApartment',
cte.MULTI_FAMILY_HOUSE: 'HighriseApartment', cte.MULTI_FAMILY_HOUSE: 'HighriseApartment',
cte.ROW_HOUSE: 'MidriseApartment', cte.ROW_HOUSE: 'MidriseApartment',
cte.MID_RISE_APARTMENT: 'MidriseApartment', cte.MID_RISE_APARTMENT: 'MidriseApartment',
cte.HIGH_RISE_APARTMENT: 'HighriseApartment', cte.HIGH_RISE_APARTMENT: 'HighriseApartment',
cte.OFFICE_AND_ADMINISTRATION: 'MediumOffice', cte.OFFICE_AND_ADMINISTRATION: 'MediumOffice',
cte.SMALL_OFFICE: 'SmallOffice', cte.SMALL_OFFICE: 'SmallOffice',
cte.MEDIUM_OFFICE: 'MediumOffice', cte.MEDIUM_OFFICE: 'MediumOffice',
cte.LARGE_OFFICE: 'LargeOffice', cte.LARGE_OFFICE: 'LargeOffice',
cte.COURTHOUSE: 'MediumOffice', cte.COURTHOUSE: 'MediumOffice',
cte.FIRE_STATION: 'n/a', cte.FIRE_STATION: 'n/a',
cte.PENITENTIARY: 'LargeHotel', cte.PENITENTIARY: 'LargeHotel',
cte.POLICE_STATION: 'n/a', cte.POLICE_STATION: 'n/a',
cte.POST_OFFICE: 'MediumOffice', cte.POST_OFFICE: 'MediumOffice',
cte.LIBRARY: 'MediumOffice', cte.LIBRARY: 'MediumOffice',
cte.EDUCATION: 'SecondarySchool', cte.EDUCATION: 'SecondarySchool',
cte.PRIMARY_SCHOOL: 'PrimarySchool', cte.PRIMARY_SCHOOL: 'PrimarySchool',
cte.PRIMARY_SCHOOL_WITH_SHOWER: 'PrimarySchool', cte.PRIMARY_SCHOOL_WITH_SHOWER: 'PrimarySchool',
cte.SECONDARY_SCHOOL: 'SecondarySchool', cte.SECONDARY_SCHOOL: 'SecondarySchool',
cte.UNIVERSITY: 'SecondarySchool', cte.UNIVERSITY: 'SecondarySchool',
cte.LABORATORY_AND_RESEARCH_CENTER: 'SecondarySchool', cte.LABORATORY_AND_RESEARCH_CENTER: 'SecondarySchool',
cte.STAND_ALONE_RETAIL: 'RetailStandalone', cte.STAND_ALONE_RETAIL: 'RetailStandalone',
cte.HOSPITAL: 'Hospital', cte.HOSPITAL: 'Hospital',
cte.OUT_PATIENT_HEALTH_CARE: 'Outpatient', cte.OUT_PATIENT_HEALTH_CARE: 'Outpatient',
cte.HEALTH_CARE: 'Outpatient', cte.HEALTH_CARE: 'Outpatient',
cte.RETIREMENT_HOME_OR_ORPHANAGE: 'SmallHotel', cte.RETIREMENT_HOME_OR_ORPHANAGE: 'SmallHotel',
cte.COMMERCIAL: 'RetailStripmall', cte.COMMERCIAL: 'RetailStripmall',
cte.STRIP_MALL: 'RetailStripmall', cte.STRIP_MALL: 'RetailStripmall',
cte.SUPERMARKET: 'RetailStripmall', cte.SUPERMARKET: 'RetailStripmall',
cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'RetailStandalone', cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'RetailStandalone',
cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'RetailStandalone', cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'RetailStandalone',
cte.RESTAURANT: 'FullServiceRestaurant', cte.RESTAURANT: 'FullServiceRestaurant',
cte.QUICK_SERVICE_RESTAURANT: 'QuickServiceRestaurant', cte.QUICK_SERVICE_RESTAURANT: 'QuickServiceRestaurant',
cte.FULL_SERVICE_RESTAURANT: 'FullServiceRestaurant', cte.FULL_SERVICE_RESTAURANT: 'FullServiceRestaurant',
cte.HOTEL: 'SmallHotel', cte.HOTEL: 'SmallHotel',
cte.HOTEL_MEDIUM_CLASS: 'SmallHotel', cte.HOTEL_MEDIUM_CLASS: 'SmallHotel',
cte.SMALL_HOTEL: 'SmallHotel', cte.SMALL_HOTEL: 'SmallHotel',
cte.LARGE_HOTEL: 'LargeHotel', cte.LARGE_HOTEL: 'LargeHotel',
cte.DORMITORY: 'SmallHotel', cte.DORMITORY: 'SmallHotel',
cte.EVENT_LOCATION: 'n/a', cte.EVENT_LOCATION: 'n/a',
cte.CONVENTION_CENTER: 'n/a', cte.CONVENTION_CENTER: 'n/a',
cte.HALL: 'n/a', cte.HALL: 'n/a',
cte.GREEN_HOUSE: 'n/a', cte.GREEN_HOUSE: 'n/a',
cte.INDUSTRY: 'n/a', cte.INDUSTRY: 'n/a',
cte.WORKSHOP: 'n/a', cte.WORKSHOP: 'n/a',
cte.WAREHOUSE: 'Warehouse', cte.WAREHOUSE: 'Warehouse',
cte.WAREHOUSE_REFRIGERATED: 'Warehouse', cte.WAREHOUSE_REFRIGERATED: 'Warehouse',
cte.SPORTS_LOCATION: 'n/a', cte.SPORTS_LOCATION: 'n/a',
cte.SPORTS_ARENA: 'n/a', cte.SPORTS_ARENA: 'n/a',
cte.GYMNASIUM: 'n/a', cte.GYMNASIUM: 'n/a',
cte.MOTION_PICTURE_THEATRE: 'n/a', cte.MOTION_PICTURE_THEATRE: 'n/a',
cte.MUSEUM: 'n/a', cte.MUSEUM: 'n/a',
cte.PERFORMING_ARTS_THEATRE: 'n/a', cte.PERFORMING_ARTS_THEATRE: 'n/a',
cte.TRANSPORTATION: 'n/a', cte.TRANSPORTATION: 'n/a',
cte.AUTOMOTIVE_FACILITY: 'n/a', cte.AUTOMOTIVE_FACILITY: 'n/a',
cte.PARKING_GARAGE: 'n/a', cte.PARKING_GARAGE: 'n/a',
cte.RELIGIOUS: 'n/a', cte.RELIGIOUS: 'n/a',
cte.NON_HEATED: 'n/a' cte.NON_HEATED: 'n/a'
} }
@property @property
def dictionary(self) -> dict: def dictionary(self) -> dict:

View File

@ -12,66 +12,66 @@ class HubFunctionToNrelConstructionFunction:
def __init__(self): def __init__(self):
self._dictionary = { self._dictionary = {
cte.RESIDENTIAL: 'residential', cte.RESIDENTIAL: 'residential',
cte.SINGLE_FAMILY_HOUSE: 'residential', cte.SINGLE_FAMILY_HOUSE: 'residential',
cte.MULTI_FAMILY_HOUSE: 'midrise apartment', cte.MULTI_FAMILY_HOUSE: 'midrise apartment',
cte.ROW_HOUSE: 'midrise apartment', cte.ROW_HOUSE: 'midrise apartment',
cte.MID_RISE_APARTMENT: 'midrise apartment', cte.MID_RISE_APARTMENT: 'midrise apartment',
cte.HIGH_RISE_APARTMENT: 'high-rise apartment', cte.HIGH_RISE_APARTMENT: 'high-rise apartment',
cte.OFFICE_AND_ADMINISTRATION: 'medium office', cte.OFFICE_AND_ADMINISTRATION: 'medium office',
cte.SMALL_OFFICE: 'small office', cte.SMALL_OFFICE: 'small office',
cte.MEDIUM_OFFICE: 'medium office', cte.MEDIUM_OFFICE: 'medium office',
cte.LARGE_OFFICE: 'large office', cte.LARGE_OFFICE: 'large office',
cte.COURTHOUSE: 'medium office', cte.COURTHOUSE: 'medium office',
cte.FIRE_STATION: 'n/a', cte.FIRE_STATION: 'n/a',
cte.PENITENTIARY: 'large hotel', cte.PENITENTIARY: 'large hotel',
cte.POLICE_STATION: 'n/a', cte.POLICE_STATION: 'n/a',
cte.POST_OFFICE: 'medium office', cte.POST_OFFICE: 'medium office',
cte.LIBRARY: 'medium office', cte.LIBRARY: 'medium office',
cte.EDUCATION: 'secondary school', cte.EDUCATION: 'secondary school',
cte.PRIMARY_SCHOOL: 'primary school', cte.PRIMARY_SCHOOL: 'primary school',
cte.PRIMARY_SCHOOL_WITH_SHOWER: 'primary school', cte.PRIMARY_SCHOOL_WITH_SHOWER: 'primary school',
cte.SECONDARY_SCHOOL: 'secondary school', cte.SECONDARY_SCHOOL: 'secondary school',
cte.UNIVERSITY: 'secondary school', cte.UNIVERSITY: 'secondary school',
cte.LABORATORY_AND_RESEARCH_CENTER: 'secondary school', cte.LABORATORY_AND_RESEARCH_CENTER: 'secondary school',
cte.STAND_ALONE_RETAIL: 'stand-alone retail', cte.STAND_ALONE_RETAIL: 'stand-alone retail',
cte.HOSPITAL: 'hospital', cte.HOSPITAL: 'hospital',
cte.OUT_PATIENT_HEALTH_CARE: 'outpatient healthcare', cte.OUT_PATIENT_HEALTH_CARE: 'outpatient healthcare',
cte.HEALTH_CARE: 'outpatient healthcare', cte.HEALTH_CARE: 'outpatient healthcare',
cte.RETIREMENT_HOME_OR_ORPHANAGE: 'small hotel', cte.RETIREMENT_HOME_OR_ORPHANAGE: 'small hotel',
cte.COMMERCIAL: 'strip mall', cte.COMMERCIAL: 'strip mall',
cte.STRIP_MALL: 'strip mall', cte.STRIP_MALL: 'strip mall',
cte.SUPERMARKET: 'supermarket', cte.SUPERMARKET: 'supermarket',
cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'stand-alone retail', cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'stand-alone retail',
cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'stand-alone retail', cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'stand-alone retail',
cte.RESTAURANT: 'full service restaurant', cte.RESTAURANT: 'full service restaurant',
cte.QUICK_SERVICE_RESTAURANT: 'quick service restaurant', cte.QUICK_SERVICE_RESTAURANT: 'quick service restaurant',
cte.FULL_SERVICE_RESTAURANT: 'full service restaurant', cte.FULL_SERVICE_RESTAURANT: 'full service restaurant',
cte.HOTEL: 'small hotel', cte.HOTEL: 'small hotel',
cte.HOTEL_MEDIUM_CLASS: 'small hotel', cte.HOTEL_MEDIUM_CLASS: 'small hotel',
cte.SMALL_HOTEL: 'small hotel', cte.SMALL_HOTEL: 'small hotel',
cte.LARGE_HOTEL: 'large hotel', cte.LARGE_HOTEL: 'large hotel',
cte.DORMITORY: 'small hotel', cte.DORMITORY: 'small hotel',
cte.EVENT_LOCATION: 'n/a', cte.EVENT_LOCATION: 'n/a',
cte.CONVENTION_CENTER: 'n/a', cte.CONVENTION_CENTER: 'n/a',
cte.HALL: 'n/a', cte.HALL: 'n/a',
cte.GREEN_HOUSE: 'n/a', cte.GREEN_HOUSE: 'n/a',
cte.INDUSTRY: 'n/a', cte.INDUSTRY: 'n/a',
cte.WORKSHOP: 'n/a', cte.WORKSHOP: 'n/a',
cte.WAREHOUSE: 'warehouse', cte.WAREHOUSE: 'warehouse',
cte.WAREHOUSE_REFRIGERATED: 'warehouse', cte.WAREHOUSE_REFRIGERATED: 'warehouse',
cte.SPORTS_LOCATION: 'n/a', cte.SPORTS_LOCATION: 'n/a',
cte.SPORTS_ARENA: 'n/a', cte.SPORTS_ARENA: 'n/a',
cte.GYMNASIUM: 'n/a', cte.GYMNASIUM: 'n/a',
cte.MOTION_PICTURE_THEATRE: 'n/a', cte.MOTION_PICTURE_THEATRE: 'n/a',
cte.MUSEUM: 'n/a', cte.MUSEUM: 'n/a',
cte.PERFORMING_ARTS_THEATRE: 'n/a', cte.PERFORMING_ARTS_THEATRE: 'n/a',
cte.TRANSPORTATION: 'n/a', cte.TRANSPORTATION: 'n/a',
cte.AUTOMOTIVE_FACILITY: 'n/aquebec_to_hub', cte.AUTOMOTIVE_FACILITY: 'n/aquebec_to_hub',
cte.PARKING_GARAGE: 'n/a', cte.PARKING_GARAGE: 'n/a',
cte.RELIGIOUS: 'n/a', cte.RELIGIOUS: 'n/a',
cte.NON_HEATED: 'n/a' cte.NON_HEATED: 'n/a'
} }
@property @property
def dictionary(self) -> dict: def dictionary(self) -> dict:

View File

@ -12,66 +12,66 @@ class HubUsageToComnetUsage:
def __init__(self): def __init__(self):
self._dictionary = { self._dictionary = {
cte.RESIDENTIAL: 'BA Multifamily', cte.RESIDENTIAL: 'BA Multifamily',
cte.SINGLE_FAMILY_HOUSE: 'BA Multifamily', cte.SINGLE_FAMILY_HOUSE: 'BA Multifamily',
cte.MULTI_FAMILY_HOUSE: 'BA Multifamily', cte.MULTI_FAMILY_HOUSE: 'BA Multifamily',
cte.ROW_HOUSE: 'BA Multifamily', cte.ROW_HOUSE: 'BA Multifamily',
cte.MID_RISE_APARTMENT: 'BA Multifamily', cte.MID_RISE_APARTMENT: 'BA Multifamily',
cte.HIGH_RISE_APARTMENT: 'BA Multifamily', cte.HIGH_RISE_APARTMENT: 'BA Multifamily',
cte.OFFICE_AND_ADMINISTRATION: 'BA Office', cte.OFFICE_AND_ADMINISTRATION: 'BA Office',
cte.SMALL_OFFICE: 'BA Office', cte.SMALL_OFFICE: 'BA Office',
cte.MEDIUM_OFFICE: 'BA Office', cte.MEDIUM_OFFICE: 'BA Office',
cte.LARGE_OFFICE: 'BA Office', cte.LARGE_OFFICE: 'BA Office',
cte.COURTHOUSE: 'BA Courthouse', cte.COURTHOUSE: 'BA Courthouse',
cte.FIRE_STATION: 'BA Fire Station', cte.FIRE_STATION: 'BA Fire Station',
cte.PENITENTIARY: 'BA Penitentiary', cte.PENITENTIARY: 'BA Penitentiary',
cte.POLICE_STATION: 'BA Police Station', cte.POLICE_STATION: 'BA Police Station',
cte.POST_OFFICE: 'BA Post Office', cte.POST_OFFICE: 'BA Post Office',
cte.LIBRARY: 'BA Library', cte.LIBRARY: 'BA Library',
cte.EDUCATION: 'BA School/University', cte.EDUCATION: 'BA School/University',
cte.PRIMARY_SCHOOL: 'BA School/University', cte.PRIMARY_SCHOOL: 'BA School/University',
cte.PRIMARY_SCHOOL_WITH_SHOWER: 'BA School/University', cte.PRIMARY_SCHOOL_WITH_SHOWER: 'BA School/University',
cte.SECONDARY_SCHOOL: 'BA School/University', cte.SECONDARY_SCHOOL: 'BA School/University',
cte.UNIVERSITY: 'BA School/University', cte.UNIVERSITY: 'BA School/University',
cte.LABORATORY_AND_RESEARCH_CENTER: 'BA School/University', cte.LABORATORY_AND_RESEARCH_CENTER: 'BA School/University',
cte.STAND_ALONE_RETAIL: 'BA Retail', cte.STAND_ALONE_RETAIL: 'BA Retail',
cte.HOSPITAL: 'BA Hospital', cte.HOSPITAL: 'BA Hospital',
cte.OUT_PATIENT_HEALTH_CARE: 'BA Healthcare Clinic', cte.OUT_PATIENT_HEALTH_CARE: 'BA Healthcare Clinic',
cte.HEALTH_CARE: 'BA Healthcare Clinic', cte.HEALTH_CARE: 'BA Healthcare Clinic',
cte.RETIREMENT_HOME_OR_ORPHANAGE: 'BA Healthcare Clinic', cte.RETIREMENT_HOME_OR_ORPHANAGE: 'BA Healthcare Clinic',
cte.COMMERCIAL: 'BA Retail', cte.COMMERCIAL: 'BA Retail',
cte.STRIP_MALL: 'BA Retail', cte.STRIP_MALL: 'BA Retail',
cte.SUPERMARKET: 'BA Retail', cte.SUPERMARKET: 'BA Retail',
cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'BA Retail', cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'BA Retail',
cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'BA Retail', cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'BA Retail',
cte.RESTAURANT: 'BA Dining: Bar Lounge/Leisure', cte.RESTAURANT: 'BA Dining: Bar Lounge/Leisure',
cte.QUICK_SERVICE_RESTAURANT: 'BA Dining: Cafeteria/Fast Food', cte.QUICK_SERVICE_RESTAURANT: 'BA Dining: Cafeteria/Fast Food',
cte.FULL_SERVICE_RESTAURANT: 'BA Dining: Bar Lounge/Leisure', cte.FULL_SERVICE_RESTAURANT: 'BA Dining: Bar Lounge/Leisure',
cte.HOTEL: 'BA Hotel', cte.HOTEL: 'BA Hotel',
cte.HOTEL_MEDIUM_CLASS: 'BA Motel', cte.HOTEL_MEDIUM_CLASS: 'BA Motel',
cte.SMALL_HOTEL: 'BA Motel', cte.SMALL_HOTEL: 'BA Motel',
cte.LARGE_HOTEL: 'BA Hotel', cte.LARGE_HOTEL: 'BA Hotel',
cte.DORMITORY: 'BA Dormitory', cte.DORMITORY: 'BA Dormitory',
cte.EVENT_LOCATION: 'BA Convention Center', cte.EVENT_LOCATION: 'BA Convention Center',
cte.CONVENTION_CENTER: 'BA Convention Center', cte.CONVENTION_CENTER: 'BA Convention Center',
cte.HALL: 'BA Town Hall', cte.HALL: 'BA Town Hall',
cte.GREEN_HOUSE: 'n/a', cte.GREEN_HOUSE: 'n/a',
cte.INDUSTRY: 'BA Manufacturing Facility', cte.INDUSTRY: 'BA Manufacturing Facility',
cte.WORKSHOP: 'BA Workshop', cte.WORKSHOP: 'BA Workshop',
cte.WAREHOUSE: 'BA Warehouse', cte.WAREHOUSE: 'BA Warehouse',
cte.WAREHOUSE_REFRIGERATED: 'BA Warehouse', cte.WAREHOUSE_REFRIGERATED: 'BA Warehouse',
cte.SPORTS_LOCATION: 'BA Exercise Center', cte.SPORTS_LOCATION: 'BA Exercise Center',
cte.SPORTS_ARENA: 'BA Sports Arena', cte.SPORTS_ARENA: 'BA Sports Arena',
cte.GYMNASIUM: 'BA Gymnasium', cte.GYMNASIUM: 'BA Gymnasium',
cte.MOTION_PICTURE_THEATRE: 'BA Motion Picture Theater', cte.MOTION_PICTURE_THEATRE: 'BA Motion Picture Theater',
cte.MUSEUM: 'BA Museum', cte.MUSEUM: 'BA Museum',
cte.PERFORMING_ARTS_THEATRE: 'BA Performing Arts Theater', cte.PERFORMING_ARTS_THEATRE: 'BA Performing Arts Theater',
cte.TRANSPORTATION: 'BA Transportation', cte.TRANSPORTATION: 'BA Transportation',
cte.AUTOMOTIVE_FACILITY: 'BA Automotive Facility', cte.AUTOMOTIVE_FACILITY: 'BA Automotive Facility',
cte.PARKING_GARAGE: 'BA Parking Garage', cte.PARKING_GARAGE: 'BA Parking Garage',
cte.RELIGIOUS: 'BA Religious Building', cte.RELIGIOUS: 'BA Religious Building',
cte.NON_HEATED: 'n/a' cte.NON_HEATED: 'n/a'
} }
@property @property
def dictionary(self) -> dict: def dictionary(self) -> dict:

View File

@ -12,66 +12,66 @@ class HubUsageToHftUsage:
def __init__(self): def __init__(self):
self._dictionary = { self._dictionary = {
cte.RESIDENTIAL: 'residential', cte.RESIDENTIAL: 'residential',
cte.SINGLE_FAMILY_HOUSE: 'single family house', cte.SINGLE_FAMILY_HOUSE: 'single family house',
cte.MULTI_FAMILY_HOUSE: 'multifamily house', cte.MULTI_FAMILY_HOUSE: 'multifamily house',
cte.ROW_HOUSE: 'single family house', cte.ROW_HOUSE: 'single family house',
cte.MID_RISE_APARTMENT: 'multifamily house', cte.MID_RISE_APARTMENT: 'multifamily house',
cte.HIGH_RISE_APARTMENT: 'multifamily house', cte.HIGH_RISE_APARTMENT: 'multifamily house',
cte.OFFICE_AND_ADMINISTRATION: 'office and administration', cte.OFFICE_AND_ADMINISTRATION: 'office and administration',
cte.SMALL_OFFICE: 'office and administration', cte.SMALL_OFFICE: 'office and administration',
cte.MEDIUM_OFFICE: 'office and administration', cte.MEDIUM_OFFICE: 'office and administration',
cte.LARGE_OFFICE: 'office and administration', cte.LARGE_OFFICE: 'office and administration',
cte.COURTHOUSE: 'office and administration', cte.COURTHOUSE: 'office and administration',
cte.FIRE_STATION: 'office and administration', cte.FIRE_STATION: 'office and administration',
cte.PENITENTIARY: 'school with shower', cte.PENITENTIARY: 'school with shower',
cte.POLICE_STATION: 'office and administration', cte.POLICE_STATION: 'office and administration',
cte.POST_OFFICE: 'office and administration', cte.POST_OFFICE: 'office and administration',
cte.LIBRARY: 'office and administration', cte.LIBRARY: 'office and administration',
cte.EDUCATION: 'education', cte.EDUCATION: 'education',
cte.PRIMARY_SCHOOL: 'school without shower', cte.PRIMARY_SCHOOL: 'school without shower',
cte.PRIMARY_SCHOOL_WITH_SHOWER: 'school with shower', cte.PRIMARY_SCHOOL_WITH_SHOWER: 'school with shower',
cte.SECONDARY_SCHOOL: 'education', cte.SECONDARY_SCHOOL: 'education',
cte.UNIVERSITY: 'education', cte.UNIVERSITY: 'education',
cte.LABORATORY_AND_RESEARCH_CENTER: 'laboratory and research centers', cte.LABORATORY_AND_RESEARCH_CENTER: 'laboratory and research centers',
cte.STAND_ALONE_RETAIL: 'retail', cte.STAND_ALONE_RETAIL: 'retail',
cte.HOSPITAL: 'health care', cte.HOSPITAL: 'health care',
cte.OUT_PATIENT_HEALTH_CARE: 'health care', cte.OUT_PATIENT_HEALTH_CARE: 'health care',
cte.HEALTH_CARE: 'health care', cte.HEALTH_CARE: 'health care',
cte.RETIREMENT_HOME_OR_ORPHANAGE: 'Home for the aged or orphanage', cte.RETIREMENT_HOME_OR_ORPHANAGE: 'Home for the aged or orphanage',
cte.COMMERCIAL: 'retail', cte.COMMERCIAL: 'retail',
cte.STRIP_MALL: 'retail', cte.STRIP_MALL: 'retail',
cte.SUPERMARKET: 'retail shop / refrigerated food', cte.SUPERMARKET: 'retail shop / refrigerated food',
cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'retail', cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'retail',
cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'retail shop / refrigerated food', cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'retail shop / refrigerated food',
cte.RESTAURANT: 'restaurant', cte.RESTAURANT: 'restaurant',
cte.QUICK_SERVICE_RESTAURANT: 'restaurant', cte.QUICK_SERVICE_RESTAURANT: 'restaurant',
cte.FULL_SERVICE_RESTAURANT: 'restaurant', cte.FULL_SERVICE_RESTAURANT: 'restaurant',
cte.HOTEL: 'hotel', cte.HOTEL: 'hotel',
cte.HOTEL_MEDIUM_CLASS: 'hotel (Medium-class)', cte.HOTEL_MEDIUM_CLASS: 'hotel (Medium-class)',
cte.SMALL_HOTEL: 'hotel', cte.SMALL_HOTEL: 'hotel',
cte.LARGE_HOTEL: 'hotel', cte.LARGE_HOTEL: 'hotel',
cte.DORMITORY: 'dormitory', cte.DORMITORY: 'dormitory',
cte.EVENT_LOCATION: 'event location', cte.EVENT_LOCATION: 'event location',
cte.CONVENTION_CENTER: 'event location', cte.CONVENTION_CENTER: 'event location',
cte.HALL: 'hall', cte.HALL: 'hall',
cte.GREEN_HOUSE: 'green house', cte.GREEN_HOUSE: 'green house',
cte.INDUSTRY: 'industry', cte.INDUSTRY: 'industry',
cte.WORKSHOP: 'industry', cte.WORKSHOP: 'industry',
cte.WAREHOUSE: 'industry', cte.WAREHOUSE: 'industry',
cte.WAREHOUSE_REFRIGERATED: 'industry', cte.WAREHOUSE_REFRIGERATED: 'industry',
cte.SPORTS_LOCATION: 'sport location', cte.SPORTS_LOCATION: 'sport location',
cte.SPORTS_ARENA: 'sport location', cte.SPORTS_ARENA: 'sport location',
cte.GYMNASIUM: 'sport location', cte.GYMNASIUM: 'sport location',
cte.MOTION_PICTURE_THEATRE: 'event location', cte.MOTION_PICTURE_THEATRE: 'event location',
cte.MUSEUM: 'event location', cte.MUSEUM: 'event location',
cte.PERFORMING_ARTS_THEATRE: 'event location', cte.PERFORMING_ARTS_THEATRE: 'event location',
cte.TRANSPORTATION: 'n/a', cte.TRANSPORTATION: 'n/a',
cte.AUTOMOTIVE_FACILITY: 'n/a', cte.AUTOMOTIVE_FACILITY: 'n/a',
cte.PARKING_GARAGE: 'n/a', cte.PARKING_GARAGE: 'n/a',
cte.RELIGIOUS: 'event location', cte.RELIGIOUS: 'event location',
cte.NON_HEATED: 'non-heated' cte.NON_HEATED: 'non-heated'
} }
@property @property
def dictionary(self) -> dict: def dictionary(self) -> dict:

View File

@ -12,66 +12,66 @@ class HubUsageToNrcanUsage:
def __init__(self): def __init__(self):
self._dictionary = { self._dictionary = {
cte.RESIDENTIAL: 'Multi-unit residential building', cte.RESIDENTIAL: 'Multi-unit residential building',
cte.SINGLE_FAMILY_HOUSE: 'Multi-unit residential building', cte.SINGLE_FAMILY_HOUSE: 'Multi-unit residential building',
cte.MULTI_FAMILY_HOUSE: 'Multi-unit residential building', cte.MULTI_FAMILY_HOUSE: 'Multi-unit residential building',
cte.ROW_HOUSE: 'Multi-unit residential building', cte.ROW_HOUSE: 'Multi-unit residential building',
cte.MID_RISE_APARTMENT: 'Multi-unit residential building', cte.MID_RISE_APARTMENT: 'Multi-unit residential building',
cte.HIGH_RISE_APARTMENT: 'Multi-unit residential building', cte.HIGH_RISE_APARTMENT: 'Multi-unit residential building',
cte.OFFICE_AND_ADMINISTRATION: 'Office', cte.OFFICE_AND_ADMINISTRATION: 'Office',
cte.SMALL_OFFICE: 'Office', cte.SMALL_OFFICE: 'Office',
cte.MEDIUM_OFFICE: 'Office', cte.MEDIUM_OFFICE: 'Office',
cte.LARGE_OFFICE: 'Office', cte.LARGE_OFFICE: 'Office',
cte.COURTHOUSE: 'Courthouse', cte.COURTHOUSE: 'Courthouse',
cte.FIRE_STATION: 'Fire station', cte.FIRE_STATION: 'Fire station',
cte.PENITENTIARY: 'Penitentiary', cte.PENITENTIARY: 'Penitentiary',
cte.POLICE_STATION: 'Police station', cte.POLICE_STATION: 'Police station',
cte.POST_OFFICE: 'Post office', cte.POST_OFFICE: 'Post office',
cte.LIBRARY: 'Library', cte.LIBRARY: 'Library',
cte.EDUCATION: 'School/university', cte.EDUCATION: 'School/university',
cte.PRIMARY_SCHOOL: 'School/university', cte.PRIMARY_SCHOOL: 'School/university',
cte.PRIMARY_SCHOOL_WITH_SHOWER: 'School/university', cte.PRIMARY_SCHOOL_WITH_SHOWER: 'School/university',
cte.SECONDARY_SCHOOL: 'School/university', cte.SECONDARY_SCHOOL: 'School/university',
cte.UNIVERSITY: 'School/university', cte.UNIVERSITY: 'School/university',
cte.LABORATORY_AND_RESEARCH_CENTER: 'School/university', cte.LABORATORY_AND_RESEARCH_CENTER: 'School/university',
cte.STAND_ALONE_RETAIL: 'Retail', cte.STAND_ALONE_RETAIL: 'Retail area',
cte.HOSPITAL: 'Hospital', cte.HOSPITAL: 'Hospital',
cte.OUT_PATIENT_HEALTH_CARE: 'Health-care clinic', cte.OUT_PATIENT_HEALTH_CARE: 'Health-care clinic',
cte.HEALTH_CARE: 'Health-care clinic', cte.HEALTH_CARE: 'Health-care clinic',
cte.RETIREMENT_HOME_OR_ORPHANAGE: 'Health-care clinic', cte.RETIREMENT_HOME_OR_ORPHANAGE: 'Health-care clinic',
cte.COMMERCIAL: 'Retail', cte.COMMERCIAL: 'Retail area',
cte.STRIP_MALL: 'Retail', cte.STRIP_MALL: 'Retail area',
cte.SUPERMARKET: 'Retail', cte.SUPERMARKET: 'Retail area',
cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'Retail', cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'Retail area',
cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'Retail', cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'Retail area',
cte.RESTAURANT: 'Dining - bar/lounge', cte.RESTAURANT: 'Dining - bar/lounge',
cte.QUICK_SERVICE_RESTAURANT: 'Dining - cafeteria', cte.QUICK_SERVICE_RESTAURANT: 'Dining - cafeteria',
cte.FULL_SERVICE_RESTAURANT: 'Dining - bar/lounge', cte.FULL_SERVICE_RESTAURANT: 'Dining - bar/lounge',
cte.HOTEL: 'Hotel', cte.HOTEL: 'Hotel',
cte.HOTEL_MEDIUM_CLASS: 'Motel', cte.HOTEL_MEDIUM_CLASS: 'Motel',
cte.SMALL_HOTEL: 'Motel', cte.SMALL_HOTEL: 'Motel',
cte.LARGE_HOTEL: 'Hotel', cte.LARGE_HOTEL: 'Hotel',
cte.DORMITORY: 'Dormitory', cte.DORMITORY: 'Dormitory',
cte.EVENT_LOCATION: 'Convention centre', cte.EVENT_LOCATION: 'Convention centre',
cte.CONVENTION_CENTER: 'Convention centre', cte.CONVENTION_CENTER: 'Convention centre',
cte.HALL: 'Town hall', cte.HALL: 'Town hall',
cte.GREEN_HOUSE: 'n/a', cte.GREEN_HOUSE: 'n/a',
cte.INDUSTRY: 'Manufacturing facility', cte.INDUSTRY: 'Manufacturing facility',
cte.WORKSHOP: 'Workshop', cte.WORKSHOP: 'Workshop',
cte.WAREHOUSE: 'Warehouse', cte.WAREHOUSE: 'Warehouse',
cte.WAREHOUSE_REFRIGERATED: 'Warehouse - refrigerated', cte.WAREHOUSE_REFRIGERATED: 'Warehouse - refrigerated',
cte.SPORTS_LOCATION: 'Exercise centre', cte.SPORTS_LOCATION: 'Exercise centre',
cte.SPORTS_ARENA: 'Sports arena', cte.SPORTS_ARENA: 'Sports arena',
cte.GYMNASIUM: 'Gymnasium', cte.GYMNASIUM: 'Gymnasium',
cte.MOTION_PICTURE_THEATRE: 'Motion picture theatre', cte.MOTION_PICTURE_THEATRE: 'Motion picture theatre',
cte.MUSEUM: 'Museum', cte.MUSEUM: 'Museum',
cte.PERFORMING_ARTS_THEATRE: 'Performing arts theatre', cte.PERFORMING_ARTS_THEATRE: 'Performing arts theatre',
cte.TRANSPORTATION: 'Transportation', cte.TRANSPORTATION: 'Transportation',
cte.AUTOMOTIVE_FACILITY: 'Automotive facility', cte.AUTOMOTIVE_FACILITY: 'Automotive facility',
cte.PARKING_GARAGE: 'Parking garage', cte.PARKING_GARAGE: 'Parking garage',
cte.RELIGIOUS: 'Religious', cte.RELIGIOUS: 'Religious',
cte.NON_HEATED: 'n/a' cte.NON_HEATED: 'n/a'
} }
@property @property
def dictionary(self) -> dict: def dictionary(self) -> dict:

View File

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

View File

@ -15,6 +15,7 @@ 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_hft_usage import HubUsageToHftUsage
from hub.helpers.data.hub_usage_to_nrcan_usage import HubUsageToNrcanUsage from hub.helpers.data.hub_usage_to_nrcan_usage import HubUsageToNrcanUsage
class Dictionaries: class Dictionaries:
""" """
Dictionaries class Dictionaries class

View File

@ -16,6 +16,8 @@ from hub.city_model_structure.attributes.polygon import Polygon
from hub.city_model_structure.attributes.polyhedron import Polyhedron from hub.city_model_structure.attributes.polyhedron import Polyhedron
from hub.helpers.location import Location from hub.helpers.location import Location
from PIL import Image
class MapPoint: class MapPoint:
def __init__(self, x, y): def __init__(self, x, y):
@ -63,7 +65,7 @@ class GeometryHelper:
return MapPoint(((city.upper_corner[0] - coordinate[0]) * 0.5), ((city.upper_corner[1] - coordinate[1]) * 0.5)) return MapPoint(((city.upper_corner[0] - coordinate[0]) * 0.5), ((city.upper_corner[1] - coordinate[1]) * 0.5))
@staticmethod @staticmethod
def city_mapping(city, building_names=None): def city_mapping(city, building_names=None, plot=False):
""" """
Returns a shared_information dictionary like Returns a shared_information dictionary like
@ -78,6 +80,8 @@ class GeometryHelper:
y = int((city.upper_corner[1] - city.lower_corner[1]) * 0.5) + 1 y = int((city.upper_corner[1] - city.lower_corner[1]) * 0.5) + 1
city_map = [['' for _ in range(y + 1)] for _ in range(x + 1)] city_map = [['' for _ in range(y + 1)] for _ in range(x + 1)]
map_info = [[{} for _ in range(y + 1)] for _ in range(x + 1)] map_info = [[{} for _ in range(y + 1)] for _ in range(x + 1)]
img = Image.new('RGB', (x + 1, y + 1), "black") # create a new black image
city_image = img.load() # create the pixel map
for building_name in building_names: for building_name in building_names:
building = city.city_object(building_name) building = city.city_object(building_name)
line = 0 line = 0
@ -103,13 +107,14 @@ class GeometryHelper:
'line_start': (coordinate[0], coordinate[1]), 'line_start': (coordinate[0], coordinate[1]),
'line_end': (next_coordinate[0], next_coordinate[1]), 'line_end': (next_coordinate[0], next_coordinate[1]),
} }
city_image[x, y] = (100, 0, 0)
elif city_map[x][y] != building.name: elif city_map[x][y] != building.name:
neighbour = city.city_object(city_map[x][y]) neighbour = city.city_object(city_map[x][y])
neighbour_info = map_info[x][y] neighbour_info = map_info[x][y]
# prepare the keys # prepare the keys
neighbour_start_coordinate = f'{neighbour_info["line_start"][0]}_{neighbour_info["line_start"][1]}' neighbour_start_coordinate = f'{GeometryHelper.coordinate_to_map_point(neighbour_info["line_start"], city)}'
building_start_coordinate = f'{coordinate[0]}_{coordinate[1]}' building_start_coordinate = f'{GeometryHelper.coordinate_to_map_point(coordinate, city)}'
neighbour_key = f'{neighbour.name}_{neighbour_start_coordinate}_{building_start_coordinate}' neighbour_key = f'{neighbour.name}_{neighbour_start_coordinate}_{building_start_coordinate}'
building_key = f'{building.name}_{building_start_coordinate}_{neighbour_start_coordinate}' building_key = f'{building.name}_{building_start_coordinate}_{neighbour_start_coordinate}'
@ -126,6 +131,10 @@ class GeometryHelper:
'line_end': (next_coordinate[0], next_coordinate[1]), 'line_end': (next_coordinate[0], next_coordinate[1]),
'neighbour_line_start': neighbour_info['line_start'], 'neighbour_line_start': neighbour_info['line_start'],
'neighbour_line_end': neighbour_info['line_end'], 'neighbour_line_end': neighbour_info['line_end'],
'coordinate_start': f"{GeometryHelper.coordinate_to_map_point(coordinate, city)}",
'coordinate_end': f"{GeometryHelper.coordinate_to_map_point(next_coordinate, city)}",
'neighbour_start': f"{GeometryHelper.coordinate_to_map_point(neighbour_info['line_start'], city)}",
'neighbour_end': f"{GeometryHelper.coordinate_to_map_point(neighbour_info['line_end'], city)}",
'shared_points': 1 'shared_points': 1
} }
@ -142,6 +151,10 @@ class GeometryHelper:
'line_end': neighbour_info['line_end'], 'line_end': neighbour_info['line_end'],
'neighbour_line_start': (coordinate[0], coordinate[1]), 'neighbour_line_start': (coordinate[0], coordinate[1]),
'neighbour_line_end': (next_coordinate[0], next_coordinate[1]), 'neighbour_line_end': (next_coordinate[0], next_coordinate[1]),
'neighbour_start': f"{GeometryHelper.coordinate_to_map_point(coordinate, city)}",
'neighbour_end': f"{GeometryHelper.coordinate_to_map_point(next_coordinate, city)}",
'coordinate_start': f"{GeometryHelper.coordinate_to_map_point(neighbour_info['line_start'], city)}",
'coordinate_end': f"{GeometryHelper.coordinate_to_map_point(neighbour_info['line_end'], city)}",
'shared_points': 1 'shared_points': 1
} }
@ -154,6 +167,8 @@ class GeometryHelper:
elif building not in neighbour.neighbours: elif building not in neighbour.neighbours:
neighbour.neighbours.append(building) neighbour.neighbours.append(building)
line += 1 line += 1
if plot:
img.show()
return lines_information return lines_information
@staticmethod @staticmethod

View File

@ -6,7 +6,7 @@ log_dir = (Path(__file__).parent.parent / 'logs').resolve()
log_file = (log_dir / 'hub.log').resolve() log_file = (log_dir / 'hub.log').resolve()
try: try:
if not os.path.isfile(log_file): if not os.path.isfile(log_file):
if not os.path.exists: if not os.path.exists(log_dir):
os.mkdir(log_dir) os.mkdir(log_dir)
with open(log_file, 'x'): with open(log_file, 'x'):
pass pass

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 Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
import math import math
import sys import sys
from hub.hub_logger import logger
import hub.helpers.constants as cte import hub.helpers.constants as cte
from hub.catalog_factories.construction_catalog_factory import ConstructionCatalogFactory from hub.catalog_factories.construction_catalog_factory import ConstructionCatalogFactory
@ -37,10 +39,13 @@ class NrcanPhysicsParameters:
function = Dictionaries().hub_function_to_nrcan_construction_function[building.function] function = Dictionaries().hub_function_to_nrcan_construction_function[building.function]
archetype = self._search_archetype(nrcan_catalog, function, building.year_of_construction, self._climate_zone) archetype = self._search_archetype(nrcan_catalog, function, building.year_of_construction, self._climate_zone)
except KeyError: except KeyError:
logger.error(f'Building {building.name} has unknown construction archetype for building function: '
f'{building.function}, building year of construction: {building.year_of_construction} '
f'and climate zone {self._climate_zone}\n')
sys.stderr.write(f'Building {building.name} has unknown construction archetype for building function: ' sys.stderr.write(f'Building {building.name} has unknown construction archetype for building function: '
f'{building.function}, building year of construction: {building.year_of_construction} ' f'{building.function}, building year of construction: {building.year_of_construction} '
f'and climate zone {self._climate_zone}\n') f'and climate zone {self._climate_zone}\n')
return continue
# if building has no thermal zones defined from geometry, and the building will be divided in storeys, # if building has no thermal zones defined from geometry, and the building will be divided in storeys,
# one thermal zone per storey is assigned # one thermal zone per storey is assigned
if len(building.internal_zones) == 1: if len(building.internal_zones) == 1:

View File

@ -39,14 +39,14 @@ class NrelPhysicsParameters:
archetype = self._search_archetype(nrel_catalog, function, building.year_of_construction, archetype = self._search_archetype(nrel_catalog, function, building.year_of_construction,
self._climate_zone) 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 construction archetype for building function: '
f'and building year of construction: {building.year_of_construction} ' f'{building.function} 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 construction archetype for building function: '
f'and building year of construction: {building.year_of_construction} ' f'{building.function} 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')
return continue
# if building has no thermal zones defined from geometry, and the building will be divided in storeys, # if building has no thermal zones defined from geometry, and the building will be divided in storeys,
# one thermal zone per storey is assigned # one thermal zone per storey is assigned

View File

@ -6,13 +6,13 @@ Project Coder Guillermo Gutierrez Guillermo.GutierrezMorote@concordia.ca
""" """
import json import json
import trimesh.creation import numpy as np
from pyproj import Transformer from pyproj import Transformer
from shapely.geometry import Polygon as ShapelyPolygon
import hub.helpers.constants as cte import hub.helpers.constants as cte
from hub.imports.geometry.helpers.geometry_helper import GeometryHelper from hub.helpers.geometry_helper import GeometryHelper
from hub.imports.geometry.helpers.geometry_helper import GeometryHelper as igh
from hub.city_model_structure.attributes.polygon import Polygon from hub.city_model_structure.attributes.polygon import Polygon
from hub.city_model_structure.building import Building from hub.city_model_structure.building import Building
from hub.city_model_structure.building_demand.surface import Surface from hub.city_model_structure.building_demand.surface import Surface
@ -62,9 +62,12 @@ class Geojson:
surfaces = [] surfaces = []
buildings = [] buildings = []
for zone, surface_coordinates in enumerate(surfaces_coordinates): for zone, surface_coordinates in enumerate(surfaces_coordinates):
points = GeometryHelper.points_from_string(GeometryHelper.remove_last_point_from_string(surface_coordinates)) points = igh.points_from_string(igh.remove_last_point_from_string(surface_coordinates))
# geojson provides the roofs, need to be transform into grounds
points = igh.invert_points(points)
polygon = Polygon(points) polygon = Polygon(points)
surfaces.append(Surface(polygon, polygon, surface_type=cte.GROUND)) polygon.area = igh.ground_area(points)
surfaces.append(Surface(polygon, polygon))
buildings.append(Building(f'{name}_zone_{zone}', surfaces, year_of_construction, function)) buildings.append(Building(f'{name}_zone_{zone}', surfaces, year_of_construction, function))
return buildings return buildings
@ -73,22 +76,41 @@ class Geojson:
lod0_buildings = Geojson._create_buildings_lod0(name, year_of_construction, function, surface_coordinates) lod0_buildings = Geojson._create_buildings_lod0(name, year_of_construction, function, surface_coordinates)
surfaces = [] surfaces = []
buildings = [] buildings = []
for zone, lod0_building in enumerate(lod0_buildings): for zone, lod0_building in enumerate(lod0_buildings):
for surface in lod0_building.surfaces: for surface in lod0_building.grounds:
shapely_polygon = ShapelyPolygon(surface.solid_polygon.coordinates) volume = surface.solid_polygon.area * height
if not shapely_polygon.is_valid: surfaces.append(surface)
print(surface.solid_polygon.area) roof_coordinates = []
print('error?', name, surface_coordinates) # adding a roof means invert the polygon coordinates and change the Z value
continue for coordinate in surface.solid_polygon.coordinates:
mesh = trimesh.creation.extrude_polygon(shapely_polygon, height) roof_coordinate = np.array([coordinate[0], coordinate[1], height])
for face in mesh.faces: # insert the roof rotated already
points = [] roof_coordinates.insert(0, roof_coordinate)
for vertex_index in face: polygon = Polygon(roof_coordinates)
points.append(mesh.vertices[vertex_index]) roof = Surface(polygon, polygon)
polygon = Polygon(points) surfaces.append(roof)
surface = Surface(polygon, polygon) # adding a wall means add the point coordinates and the next point coordinates with Z's height and 0
surfaces.append(surface) coordinates_length = len(roof.solid_polygon.coordinates)
buildings.append(Building(f'{name}_zone_{zone}', surfaces, year_of_construction, function)) for i, coordinate in enumerate(roof.solid_polygon.coordinates):
j = i + 1
if j == coordinates_length:
j = 0
next_coordinate = roof.solid_polygon.coordinates[j]
wall_coordinates = [
np.array([coordinate[0], coordinate[1], 0.0]),
np.array([next_coordinate[0], next_coordinate[1], 0.0]),
np.array([next_coordinate[0], next_coordinate[1], next_coordinate[2]]),
np.array([coordinate[0], coordinate[1], coordinate[2]])
]
polygon = Polygon(wall_coordinates)
wall = Surface(polygon, polygon)
surfaces.append(wall)
building = Building(f'{name}_zone_{zone}', surfaces, year_of_construction, function)
building.volume = volume
buildings.append(building)
return buildings return buildings
def _get_polygons(self, polygons, coordinates): def _get_polygons(self, polygons, coordinates):
@ -106,6 +128,49 @@ class Geojson:
polygons.append(transformed_coordinates.lstrip(' ')) polygons.append(transformed_coordinates.lstrip(' '))
return polygons return polygons
@staticmethod
def _find_wall(line_1, line_2):
for i in range(0, 2):
j = 1 - i
point_1 = line_1[i]
point_2 = line_2[j]
distance = GeometryHelper.distance_between_points(point_1, point_2)
if distance > 1e-2:
return False
return True
def _store_shared_percentage_to_walls(self, city, city_mapped):
for building in city.buildings:
if building.name not in city_mapped.keys():
for wall in building.walls:
wall.percentage_shared = 0
continue
building_mapped = city_mapped[building.name]
for wall in building.walls:
percentage = 0
ground_line = []
for point in wall.perimeter_polygon.coordinates:
if point[2] < 0.5:
ground_line.append(point)
for entry in building_mapped:
if building_mapped[entry]['shared_points'] <= 3:
continue
line = [building_mapped[entry]['line_start'], building_mapped[entry]['line_end']]
neighbour_line = [building_mapped[entry]['neighbour_line_start'],
building_mapped[entry]['neighbour_line_end']]
neighbour_height = city.city_object(building_mapped[entry]['neighbour_name']).max_height
if self._find_wall(line, ground_line):
line_shared = (GeometryHelper.distance_between_points(line[0], line[1]) +
GeometryHelper.distance_between_points(neighbour_line[0], neighbour_line[1]) -
GeometryHelper.distance_between_points(line[1], neighbour_line[0]) -
GeometryHelper.distance_between_points(line[0], neighbour_line[1])) / 2
percentage_ground = line_shared / GeometryHelper.distance_between_points(line[0], line[1])
percentage_height = neighbour_height / building.max_height
if percentage_height > 1:
percentage_height = 1
percentage += percentage_ground * percentage_height
wall.percentage_shared = percentage
@property @property
def city(self) -> City: def city(self) -> City:
""" """
@ -115,6 +180,7 @@ class Geojson:
missing_functions = [] missing_functions = []
buildings = [] buildings = []
building_id = 0 building_id = 0
lod = 1
for feature in self._geojson['features']: for feature in self._geojson['features']:
extrusion_height = 0 extrusion_height = 0
if self._extrusion_height_field is not None: if self._extrusion_height_field is not None:
@ -140,7 +206,6 @@ 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):
@ -163,6 +228,9 @@ class Geojson:
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 self._city.level_of_detail.geometry = lod
if lod == 1:
lines_information = GeometryHelper.city_mapping(self._city)
self._store_shared_percentage_to_walls(self._city, lines_information)
if len(missing_functions) > 0: if len(missing_functions) > 0:
print(f'There are unknown functions {missing_functions}') print(f'There are unknown functions {missing_functions}')
return self._city return self._city

View File

@ -4,6 +4,8 @@ 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 math
import sys
import numpy as np import numpy as np
@ -45,3 +47,69 @@ class GeometryHelper:
array = points.split(' ') array = points.split(' ')
res = " " res = " "
return res.join(array[0:len(array) - 3]) return res.join(array[0:len(array) - 3])
@staticmethod
def invert_points(points):
res = []
for point in points:
res.insert(0,point)
return res
@staticmethod
def ground_area(points):
"""
Get ground surface area in square meters
:return: float
"""
# New method to calculate area
if len(points) < 3:
sys.stderr.write('Warning: the area of a line or point cannot be calculated 1. Area = 0\n')
return 0
alpha = 0
vec_1 = points[1] - points[0]
for i in range(2, len(points)):
vec_2 = points[i] - points[0]
alpha += GeometryHelper.angle_between_vectors(vec_1, vec_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 = points
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])
_area = abs(area)
return _area
@staticmethod
def angle_between_vectors(vec_1, vec_2):
"""
angle between vectors in radians
:param vec_1: vector
:param vec_2: vector
:return: float
"""
if np.linalg.norm(vec_1) == 0 or np.linalg.norm(vec_2) == 0:
sys.stderr.write("Warning: impossible to calculate angle between planes' normal. Return 0\n")
return 0
cosine = np.dot(vec_1, vec_2) / np.linalg.norm(vec_1) / np.linalg.norm(vec_2)
if cosine > 1 and cosine - 1 < 1e-5:
cosine = 1
elif cosine < -1 and cosine + 1 > -1e-5:
cosine = -1
alpha = math.acos(cosine)
return alpha
@staticmethod
def invert_points(points):
res = []
for point in points:
res.insert(0,point)
return res

View File

@ -10,6 +10,7 @@ import pandas as pd
import csv import csv
import hub.helpers.constants as cte import hub.helpers.constants as cte
class InselMonthlyEnergyBalance: class InselMonthlyEnergyBalance:
""" """
Import SRA results Import SRA results

View File

@ -8,6 +8,7 @@ import copy
import sys import sys
import numpy import numpy
from hub.hub_logger import logger
import hub.helpers.constants as cte import hub.helpers.constants as cte
from hub.helpers.dictionaries import Dictionaries from hub.helpers.dictionaries import Dictionaries
from hub.city_model_structure.building_demand.usage import Usage from hub.city_model_structure.building_demand.usage import Usage
@ -15,6 +16,7 @@ from hub.city_model_structure.building_demand.lighting import Lighting
from hub.city_model_structure.building_demand.occupancy import Occupancy from hub.city_model_structure.building_demand.occupancy import Occupancy
from hub.city_model_structure.building_demand.appliances import Appliances 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.thermal_control import ThermalControl
from hub.city_model_structure.building_demand.domestic_hot_water import DomesticHotWater
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.internal_gain import InternalGain from hub.city_model_structure.building_demand.internal_gain import InternalGain
from hub.catalog_factories.usage_catalog_factory import UsageCatalogFactory from hub.catalog_factories.usage_catalog_factory import UsageCatalogFactory
@ -40,9 +42,9 @@ class ComnetUsageParameters:
try: try:
archetype_usage = self._search_archetypes(comnet_catalog, usage_name) archetype_usage = self._search_archetypes(comnet_catalog, usage_name)
except KeyError: except KeyError:
sys.stderr.write(f'Building {building.name} has unknown usage archetype for building function:' logger.error(f'Building {building.name} has unknown usage archetype for usage: {usage_name}')
f' {building.function}') sys.stderr.write(f'Building {building.name} has unknown usage archetype for usage: {usage_name}')
return continue
for internal_zone in building.internal_zones: for internal_zone in building.internal_zones:
if internal_zone.area is None: if internal_zone.area is None:
@ -54,7 +56,7 @@ class ComnetUsageParameters:
volume_per_area = internal_zone.volume / internal_zone.area volume_per_area = internal_zone.volume / internal_zone.area
usage = Usage() usage = Usage()
usage.name = usage_name usage.name = usage_name
self._assign_values(usage, archetype_usage, volume_per_area) self._assign_values(usage, archetype_usage, volume_per_area, building.cold_water_temperature)
usage.percentage = 1 usage.percentage = 1
self._calculate_reduced_values_from_extended_library(usage, archetype_usage) self._calculate_reduced_values_from_extended_library(usage, archetype_usage)
@ -69,7 +71,7 @@ class ComnetUsageParameters:
raise KeyError('archetype not found') raise KeyError('archetype not found')
@staticmethod @staticmethod
def _assign_values(usage, archetype, volume_per_area): def _assign_values(usage, archetype, volume_per_area, cold_water_temperature):
# Due to the fact that python is not a typed language, the wrong object type is assigned to # Due to the fact that python is not a typed language, the wrong object type is assigned to
# usage.occupancy when writing usage.occupancy = archetype.occupancy. # usage.occupancy when writing usage.occupancy = archetype.occupancy.
# Same happens for lighting and appliances. Therefore, this walk around has been done. # Same happens for lighting and appliances. Therefore, this walk around has been done.
@ -101,6 +103,17 @@ class ComnetUsageParameters:
_control.heating_set_point_schedules = archetype.thermal_control.heating_set_point_schedules _control.heating_set_point_schedules = archetype.thermal_control.heating_set_point_schedules
_control.hvac_availability_schedules = archetype.thermal_control.hvac_availability_schedules _control.hvac_availability_schedules = archetype.thermal_control.hvac_availability_schedules
usage.thermal_control = _control usage.thermal_control = _control
_domestic_hot_water = DomesticHotWater()
_domestic_hot_water.density = archetype.domestic_hot_water.density
_domestic_hot_water.service_temperature = archetype.domestic_hot_water.service_temperature
cold_temperature = cold_water_temperature[cte.YEAR]['epw']
peak_flow = 0
if (archetype.domestic_hot_water.service_temperature - cold_temperature) > 0:
peak_flow = archetype.domestic_hot_water.density / cte.WATER_DENSITY / cte.WATER_HEAT_CAPACITY \
/ (archetype.domestic_hot_water.service_temperature - cold_temperature)
_domestic_hot_water.peak_flow = peak_flow
_domestic_hot_water.schedules = archetype.domestic_hot_water.schedules
usage.domestic_hot_water = _domestic_hot_water
@staticmethod @staticmethod
def _calculate_reduced_values_from_extended_library(usage, archetype): def _calculate_reduced_values_from_extended_library(usage, archetype):

View File

@ -7,6 +7,7 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
import sys import sys
from hub.hub_logger import logger
import hub.helpers.constants as cte import hub.helpers.constants as cte
from hub.helpers.dictionaries import Dictionaries from hub.helpers.dictionaries import Dictionaries
from hub.city_model_structure.building_demand.usage import Usage from hub.city_model_structure.building_demand.usage import Usage
@ -14,6 +15,7 @@ from hub.city_model_structure.building_demand.lighting import Lighting
from hub.city_model_structure.building_demand.occupancy import Occupancy from hub.city_model_structure.building_demand.occupancy import Occupancy
from hub.city_model_structure.building_demand.appliances import Appliances 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.thermal_control import ThermalControl
from hub.city_model_structure.building_demand.domestic_hot_water import DomesticHotWater
from hub.catalog_factories.usage_catalog_factory import UsageCatalogFactory from hub.catalog_factories.usage_catalog_factory import UsageCatalogFactory
@ -39,17 +41,17 @@ class NrcanUsageParameters:
try: try:
archetype_usage = self._search_archetypes(nrcan_catalog, usage_name) archetype_usage = self._search_archetypes(nrcan_catalog, usage_name)
except KeyError: except KeyError:
sys.stderr.write(f'Building {building.name} has unknown usage archetype for building function:' logger.error(f'Building {building.name} has unknown usage archetype for usage: {usage_name}\n')
f' {building.function}') sys.stderr.write(f'Building {building.name} has unknown usage archetype for usage: {usage_name}\n')
return continue
usage_name = Dictionaries().hub_usage_to_comnet_usage[building.function] usage_name = Dictionaries().hub_usage_to_comnet_usage[building.function]
try: try:
comnet_archetype_usage = self._search_archetypes(comnet_catalog, usage_name) comnet_archetype_usage = self._search_archetypes(comnet_catalog, usage_name)
except KeyError: except KeyError:
sys.stderr.write(f'Building {building.name} has unknown usage archetype for building function:' logger.error(f'Building {building.name} has unknown usage archetype for usage: {usage_name}\n')
f' {building.function}') sys.stderr.write(f'Building {building.name} has unknown usage archetype for usage: {usage_name}\n')
return continue
for internal_zone in building.internal_zones: for internal_zone in building.internal_zones:
if internal_zone.area is None: if internal_zone.area is None:
@ -61,7 +63,7 @@ class NrcanUsageParameters:
volume_per_area = internal_zone.volume / internal_zone.area volume_per_area = internal_zone.volume / internal_zone.area
usage = Usage() usage = Usage()
usage.name = usage_name usage.name = usage_name
self._assign_values(usage, archetype_usage, volume_per_area) self._assign_values(usage, archetype_usage, volume_per_area, building.cold_water_temperature)
self._assign_comnet_extra_values(usage, comnet_archetype_usage) self._assign_comnet_extra_values(usage, comnet_archetype_usage)
usage.percentage = 1 usage.percentage = 1
self._calculate_reduced_values_from_extended_library(usage, archetype_usage) self._calculate_reduced_values_from_extended_library(usage, archetype_usage)
@ -77,7 +79,7 @@ class NrcanUsageParameters:
raise KeyError('archetype not found') raise KeyError('archetype not found')
@staticmethod @staticmethod
def _assign_values(usage, archetype, volume_per_area): def _assign_values(usage, archetype, volume_per_area, cold_water_temperature):
if archetype.mechanical_air_change > 0: if archetype.mechanical_air_change > 0:
usage.mechanical_air_change = archetype.mechanical_air_change usage.mechanical_air_change = archetype.mechanical_air_change
elif archetype.ventilation_rate > 0: elif archetype.ventilation_rate > 0:
@ -111,6 +113,14 @@ class NrcanUsageParameters:
_control.heating_set_point_schedules = archetype.thermal_control.heating_set_point_schedules _control.heating_set_point_schedules = archetype.thermal_control.heating_set_point_schedules
_control.hvac_availability_schedules = archetype.thermal_control.hvac_availability_schedules _control.hvac_availability_schedules = archetype.thermal_control.hvac_availability_schedules
usage.thermal_control = _control usage.thermal_control = _control
_domestic_hot_water = DomesticHotWater()
_domestic_hot_water.peak_flow = archetype.domestic_hot_water.peak_flow
_domestic_hot_water.service_temperature = archetype.domestic_hot_water.service_temperature
cold_temperature = cold_water_temperature[cte.YEAR]['epw']
_domestic_hot_water.density = archetype.domestic_hot_water.peak_flow * cte.WATER_DENSITY * cte.WATER_HEAT_CAPACITY \
* (archetype.domestic_hot_water.service_temperature - cold_temperature)
_domestic_hot_water.schedules = archetype.domestic_hot_water.schedules
usage.domestic_hot_water = _domestic_hot_water
@staticmethod @staticmethod
def _assign_comnet_extra_values(usage, archetype): def _assign_comnet_extra_values(usage, archetype):

View File

@ -32,14 +32,13 @@ class EpwWeatherParameters:
_ = file.readline().split(',') _ = file.readline().split(',')
line = file.readline().split(',') line = file.readline().split(',')
number_records = int(line[1]) number_records = int(line[1])
depth_measurement_ground_temperature = [] ground_temperature = {}
ground_temperature = []
for i in range(0, number_records): for i in range(0, number_records):
depth_measurement_ground_temperature.append(line[i*16+2]) depth_measurement_ground_temperature = line[i*16+2]
temperatures = [] temperatures = []
for j in range(0, 12): for j in range(0, 12):
temperatures.append(line[i*16+j+6]) temperatures.append(line[i*16+j+6])
ground_temperature.append(temperatures) ground_temperature[depth_measurement_ground_temperature] = temperatures
file.close() file.close()
except SystemExit: except SystemExit:
sys.stderr.write(f'Error: weather file {self._path} not found. Please download it from ' sys.stderr.write(f'Error: weather file {self._path} not found. Please download it from '
@ -74,6 +73,7 @@ class EpwWeatherParameters:
sys.exit() sys.exit()
for building in self._city.buildings: for building in self._city.buildings:
building.ground_temperature[cte.MONTH] = ground_temperature
if cte.HOUR in building.external_temperature: if cte.HOUR in building.external_temperature:
del building.external_temperature[cte.HOUR] del building.external_temperature[cte.HOUR]
new_value = pd.DataFrame(self._weather_values[['dry_bulb_temperature_c']].to_numpy(), columns=['epw']) new_value = pd.DataFrame(self._weather_values[['dry_bulb_temperature_c']].to_numpy(), columns=['epw'])
@ -111,10 +111,24 @@ class EpwWeatherParameters:
building.beam[cte.HOUR] = new_value building.beam[cte.HOUR] = new_value
else: else:
pd.concat([building.beam[cte.HOUR], new_value], axis=1) pd.concat([building.beam[cte.HOUR], new_value], axis=1)
new_value = wh().cold_water_temperature(building.external_temperature[cte.HOUR]['epw'])
if cte.HOUR not in building.cold_water_temperature:
building.cold_water_temperature[cte.HOUR] = new_value
else:
pd.concat([building.cold_water_temperature[cte.HOUR], new_value], axis=1)
# create the monthly and yearly values out of the hourly # create the monthly and yearly values out of the hourly
for building in self._city.buildings: for building in self._city.buildings:
if cte.MONTH not in building.external_temperature: if cte.MONTH not in building.external_temperature:
building.external_temperature[cte.MONTH] = wh().get_monthly_mean_values(building.external_temperature[cte.HOUR][['epw']]) building.external_temperature[cte.MONTH] = \
wh().get_monthly_mean_values(building.external_temperature[cte.HOUR][['epw']])
if cte.YEAR not in building.external_temperature: if cte.YEAR not in building.external_temperature:
building.external_temperature[cte.YEAR] = wh(). get_yearly_mean_values(building.external_temperature[cte.HOUR][['epw']]) building.external_temperature[cte.YEAR] = \
wh(). get_yearly_mean_values(building.external_temperature[cte.HOUR][['epw']])
if cte.MONTH not in building.cold_water_temperature:
building.cold_water_temperature[cte.MONTH] = wh().get_monthly_mean_values(
building.cold_water_temperature[cte.HOUR][['epw']])
if cte.YEAR not in building.cold_water_temperature:
building.cold_water_temperature[cte.YEAR] = wh().get_yearly_mean_values(
building.cold_water_temperature[cte.HOUR][['epw']])
self._city.level_of_detail.weather = 2 self._city.level_of_detail.weather = 2

View File

@ -4,6 +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 math import math
import hub.helpers.constants as cte import hub.helpers.constants as cte
import pandas as pd import pandas as pd
@ -20,7 +21,7 @@ class Weather:
def sky_temperature(ambient_temperature): def sky_temperature(ambient_temperature):
""" """
Get sky temperature from ambient temperature in Celsius Get sky temperature from ambient temperature in Celsius
:return: float :return: List[float]
""" """
# Swinbank - Source sky model approximation(1963) based on cloudiness statistics(32 %) in United States # Swinbank - Source sky model approximation(1963) based on cloudiness statistics(32 %) in United States
# ambient temperatures( in °C) # ambient temperatures( in °C)
@ -32,6 +33,37 @@ class Weather:
values.append(value) values.append(value)
return values return values
@staticmethod
def cold_water_temperature(ambient_temperature):
"""
Get cold water temperature from ambient temperature in Celsius
:return: dict
"""
# Equation from "TOWARDS DEVELOPMENT OF AN ALGORITHM FOR MAINS WATER TEMPERATURE", 2004, Jay Burch
# and Craig Christensen, National Renewable Energy Laboratory
# ambient temperatures( in °C)
# cold water temperatures( in °C)
ambient_temperature_fahrenheit = []
average_temperature = 0
maximum_temperature = -1000
minimum_temperature = 1000
for temperature in ambient_temperature:
value = temperature * 9 / 5 + 32
ambient_temperature_fahrenheit.append(value)
average_temperature += value / 8760
if value > maximum_temperature:
maximum_temperature = value
if value < minimum_temperature:
minimum_temperature = value
delta_temperature = maximum_temperature - minimum_temperature
ratio = 0.4 + 0.01 * (average_temperature - 44)
lag = 35 - 1 * (average_temperature - 44)
cold_temperature = []
for temperature in ambient_temperature_fahrenheit:
radians = (0.986 * (temperature-15-lag) - 90) * math.pi / 180
cold_temperature.append((average_temperature + 6 + ratio * (delta_temperature/2) * math.sin(radians) - 32) * 5/9)
return pd.DataFrame(cold_temperature, columns=['epw'])
def get_monthly_mean_values(self, values): def get_monthly_mean_values(self, values):
out = None out = None
if values is not None: if values is not None:
@ -41,7 +73,8 @@ class Weather:
del out['month'] del out['month']
return out return out
def get_yearly_mean_values(self, values): @staticmethod
def get_yearly_mean_values(values):
return values.mean() return values.mean()
def get_total_month(self, values): def get_total_month(self, values):

View File

@ -121,7 +121,24 @@ class City(Repository):
result_set = self.session.execute(select(Model).where(Model.user_id == user_id, result_set = self.session.execute(select(Model).where(Model.user_id == user_id,
Model.application_id == application_id, Model.application_id == application_id,
Model.name == city_name Model.name == city_name
)).first()[0] )).first()
if result_set is not None:
result_set = result_set[0]
return result_set return result_set
except SQLAlchemyError as err: except SQLAlchemyError as err:
logger.error(f'Error while fetching city by name: {err}') logger.error(f'Error while fetching city by name: {err}')
def get_by_user_id_and_application_id(self, user_id, application_id) -> [Model]:
"""
Fetch city based on the user who created it
:param user_id: the user id
:param application_id: the application id
:return: ModelCity
"""
try:
result_set = self.session.execute(
select(Model).where(Model.user_id == user_id, Model.application_id == application_id)
)
return [r[0] for r in result_set]
except SQLAlchemyError as err:
logger.error(f'Error while fetching city by name: {err}')

View File

@ -105,7 +105,7 @@ class CityObject(Repository):
except SQLAlchemyError as err: except SQLAlchemyError as err:
logger.error(f'Error while deleting application: {err}') logger.error(f'Error while deleting application: {err}')
def get_by_name_and_city(self, name, city_id) -> [Model]: def get_by_name_and_city(self, name, city_id) -> Union[Model, None]:
""" """
Fetch a city object based on name and city id Fetch a city object based on name and city id
:param name: city object name :param name: city object name

View File

@ -10,6 +10,7 @@ from typing import Union, Dict
from sqlalchemy import select from sqlalchemy import select
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy import or_
from hub.hub_logger import logger from hub.hub_logger import logger
from hub.persistence import Repository from hub.persistence import Repository
@ -98,7 +99,7 @@ class SimulationResults(Repository):
Deletes an application with the application_uuid Deletes an application with the application_uuid
:param name: The simulation results tool and workflow name :param name: The simulation results tool and workflow name
:param city_id: The id for the city owning the simulation results :param city_id: The id for the city owning the simulation results
:param city_object_id: the id for the city_object ownning these simulation results :param city_object_id: the id for the city_object owning these simulation results
:return: None :return: None
""" """
@ -125,28 +126,6 @@ class SimulationResults(Repository):
except SQLAlchemyError as err: except SQLAlchemyError as err:
logger.error(f'Error while fetching city by city_id: {err}') logger.error(f'Error while fetching city by city_id: {err}')
def get_simulation_results_by_city_id(self, city_id) -> [Model]:
"""
Fetch simulation results by name
:param city_id: the id of the city
:return: [Model] with the provided city id
"""
try:
return self.session.execute(select(Model).where(Model.city_id == city_id))
except SQLAlchemyError as err:
logger.error(f'Error while fetching simulation results by name: {err}')
def get_simulation_results_by_city_object_id(self, city_object_id) -> [Model]:
"""
Fetch simulation results by name
:param city_object_id: the id of the city object
:return: [Model] with the provided city object id
"""
try:
return self.session.execute(select(Model).where(Model.city_object_id == city_object_id))
except SQLAlchemyError as err:
logger.error(f'Error while fetching simulation results by name: {err}')
def _get_city_object(self, city_object_id) -> [CityObject]: def _get_city_object(self, city_object_id) -> [CityObject]:
""" """
Fetch a city object based city id Fetch a city object based city id
@ -157,3 +136,27 @@ class SimulationResults(Repository):
return self.session.execute(select(CityObject).where(CityObject.id == city_object_id)).first() return self.session.execute(select(CityObject).where(CityObject.id == city_object_id)).first()
except SQLAlchemyError as err: except SQLAlchemyError as err:
logger.error(f'Error while fetching city by city_id: {err}') logger.error(f'Error while fetching city by city_id: {err}')
def get_simulation_results_by_city_id_city_object_id_and_names(self, city_id, city_object_id, result_names=[]):
"""
Fetch the simulation results based in the city_id or city_object_id with the given names or all
:param city_id: the city id
:param city_object_id: the city object id
:param result_names: if given filter the results
:return: [SimulationResult]
"""
try:
result_set = self.session.execute(select(Model).where(or_(
Model.city_id == city_id,
Model.city_object_id == city_object_id
)))
results = [r[0] for r in result_set]
if not result_names:
return results
_ = []
for result in results:
if result.name in result_names:
_.append(result)
return _
except SQLAlchemyError as err:
logger.error(f'Error while fetching city by city_id: {err}')

View File

@ -60,7 +60,7 @@ class User(Repository):
:param name: the name of the user :param name: the name of the user
:param password: the password of the user :param password: the password of the user
:param role: the role of the user :param role: the role of the user
:return: :return: None, Dictionary
""" """
try: try:
self.session.query(Model).filter(Model.id == user_id).update({ self.session.query(Model).filter(Model.id == user_id).update({
@ -86,28 +86,30 @@ class User(Repository):
except SQLAlchemyError as err: except SQLAlchemyError as err:
logger.error(f'Error while fetching user: {err}') logger.error(f'Error while fetching user: {err}')
def get_by_name_and_application(self, name: str, application_id: int) -> [Model]: def get_by_name_and_application(self, name: str, application_id: int) -> Union[Model, None]:
""" """
Fetch user based on the email address Fetch user based on the email address
:param name: User name :param name: User name
:param application_id: User application name :param application_id: User application name
:return: [User] matching the search criteria :return: User matching the search criteria or None
""" """
try: try:
return self.session.execute( user = self.session.execute(
select(Model).where(Model.name == name, Model.application_id == application_id) select(Model).where(Model.name == name, Model.application_id == application_id)
).first() ).first()
if user is not None:
user = user[0]
return user
except SQLAlchemyError as err: except SQLAlchemyError as err:
logger.error(f'Error while fetching user by name and application: {err}') logger.error(f'Error while fetching user by name and application: {err}')
def get_by_name_application_id_and_password(self, name: str, password: str, application_id: int) -> [Model]: def get_by_name_application_id_and_password(self, name: str, password: str, application_id: int) -> Union[Model, None]:
""" """
Fetch user based on the email and password Fetch user based on the email and password
:param name: User name :param name: User name
:param password: User password :param password: User password
:param application_id: User password :param application_id: User password
:return: User
:return: [User]
""" """
try: try:
user = self.session.execute( user = self.session.execute(
@ -119,14 +121,13 @@ class User(Repository):
except SQLAlchemyError as err: except SQLAlchemyError as err:
logger.error(f'Error while fetching user by email: {err}') logger.error(f'Error while fetching user by email: {err}')
def get_by_name_application_uuid_and_password(self, name: str, password: str, application_uuid: str) -> [Model]: def get_by_name_application_uuid_and_password(self, name: str, password: str, application_uuid: str) -> Union[Model, None]:
""" """
Fetch user based on the email and password Fetch user based on the email and password
:param name: User name :param name: User name
:param password: User password :param password: User password
:param application_uuid: Application uuid :param application_uuid: Application uuid
:return: User
:return: [User]
""" """
try: try:
application = self.session.execute( application = self.session.execute(

View File

@ -23,3 +23,4 @@ shapely
geopandas geopandas
triangle triangle
psycopg2-binary psycopg2-binary
PIL

View File

@ -71,8 +71,6 @@ class TestExports(TestCase):
self._complete_city = self._get_complete_city(from_pickle) self._complete_city = self._get_complete_city(from_pickle)
EnergyBuildingsExportsFactory(export_type, self._complete_city, self._output_path).export() EnergyBuildingsExportsFactory(export_type, self._complete_city, self._output_path).export()
def test_obj_export(self): def test_obj_export(self):
""" """
export to obj export to obj

View File

@ -118,7 +118,6 @@ class TestGeometryFactory(TestCase):
city = self._get_city(file, 'rhino') city = self._get_city(file, 'rhino')
self.assertIsNotNone(city, 'city is none') self.assertIsNotNone(city, 'city is none')
self.assertTrue(len(city.buildings) == 36) self.assertTrue(len(city.buildings) == 36)
i = 0
def test_import_obj(self): def test_import_obj(self):
""" """
@ -135,14 +134,19 @@ class TestGeometryFactory(TestCase):
""" """
Test geojson import Test geojson import
""" """
file = 'concordia.geojson' file = '2000_buildings.geojson'
start = datetime.datetime.now()
city = self._get_city(file, 'geojson', city = self._get_city(file, 'geojson',
height_field='citygml_me', height_field='building_height',
year_of_construction_field='ANNEE_CONS', year_of_construction_field='ANNEE_CONS',
function_field='CODE_UTILI') function_field='CODE_UTILI')
end = datetime.datetime.now()
print(f'geometry load in {end-start} s')
start = datetime.datetime.now()
hub.exports.exports_factory.ExportsFactory('obj', city, self._output_path).export() hub.exports.exports_factory.ExportsFactory('obj', city, self._output_path).export()
self.assertEqual(207, len(city.buildings), 'wrong number of buildings') end = datetime.datetime.now()
print(f'geometry export in {end - start} s')
self.assertEqual(2356, len(city.buildings), 'wrong number of buildings')
self._check_buildings(city) self._check_buildings(city)
def test_map_neighbours(self): def test_map_neighbours(self):
@ -154,7 +158,13 @@ class TestGeometryFactory(TestCase):
height_field='citygml_me', height_field='citygml_me',
year_of_construction_field='ANNEE_CONS', year_of_construction_field='ANNEE_CONS',
function_field='LIBELLE_UT') function_field='LIBELLE_UT')
GeometryHelper.city_mapping(city) info_lod1 = GeometryHelper.city_mapping(city, plot=False)
city = self._get_city(file, 'geojson',
year_of_construction_field='ANNEE_CONS',
function_field='LIBELLE_UT')
info_lod0 = GeometryHelper.city_mapping(city, plot=False)
hub.exports.exports_factory.ExportsFactory('obj', city, self._output_path).export()
self.assertEqual(info_lod0, info_lod1)
for building in city.buildings: for building in city.buildings:
self.assertEqual(2, len(building.neighbours)) self.assertEqual(2, len(building.neighbours))
@ -164,4 +174,3 @@ class TestGeometryFactory(TestCase):
self.assertEqual('3_part_0_zone_0',city.city_object('2_part_0_zone_0').neighbours[1].name) self.assertEqual('3_part_0_zone_0',city.city_object('2_part_0_zone_0').neighbours[1].name)
self.assertEqual('1_part_0_zone_0', city.city_object('3_part_0_zone_0').neighbours[0].name) self.assertEqual('1_part_0_zone_0', city.city_object('3_part_0_zone_0').neighbours[0].name)
self.assertEqual('2_part_0_zone_0', city.city_object('3_part_0_zone_0').neighbours[1].name) self.assertEqual('2_part_0_zone_0', city.city_object('3_part_0_zone_0').neighbours[1].name)

View File

@ -124,3 +124,7 @@ class TestUsageFactory(TestCase):
self.assertIsNotNone(appliances.schedules, 'appliances schedule is none') self.assertIsNotNone(appliances.schedules, 'appliances schedule is none')
self.assertIsNotNone(usage.thermal_control.hvac_availability_schedules, self.assertIsNotNone(usage.thermal_control.hvac_availability_schedules,
'control hvac availability is none') 'control hvac availability is none')
self.assertIsNotNone(usage.domestic_hot_water.density, 'domestic hot water density is none')
self.assertIsNotNone(usage.domestic_hot_water.service_temperature,
'domestic hot water service temperature is none')
self.assertIsNotNone(usage.domestic_hot_water.schedules, 'domestic hot water schedules is none')

File diff suppressed because one or more lines are too long

View File

@ -12,18 +12,18 @@
-73.580414175680588, -73.580414175680588,
45.497641136608358 45.497641136608358
], ],
[
-73.581414175680588,
45.497641136608358
],
[
-73.581414175680588,
45.498641136608358
],
[ [
-73.580414175680588, -73.580414175680588,
45.498641136608358 45.498641136608358
], ],
[
-73.581414175680588,
45.498641136608358
],
[
-73.581414175680588,
45.497641136608358
],
[ [
-73.580414175680588, -73.580414175680588,
45.497641136608358 45.497641136608358
@ -204,19 +204,20 @@
[ [
-73.581414175680588, -73.581414175680588,
45.497641136608358 45.497641136608358
]
,
[
-73.581414175680588,
45.498441136608358
],
[
-73.582214175680588,
45.498441136608358
], ],
[ [
-73.582214175680588, -73.582214175680588,
45.497641136608358 45.497641136608358
], ],
[
-73.582214175680588,
45.498441136608358
],
[
-73.581414175680588,
45.498441136608358
],
[ [
-73.581414175680588, -73.581414175680588,
45.497641136608358 45.497641136608358
@ -399,31 +400,30 @@
-73.581914175680588, -73.581914175680588,
45.498441136608358 45.498441136608358
], ],
[
-73.581914175680588,
45.499641136608358
],
[
-73.580914175680588,
45.499641136608358
],
[
-73.580914175680588,
45.498641136608358
],
[
-73.581414175680588,
45.498641136608358
],
[ [
-73.581414175680588, -73.581414175680588,
45.498441136608358 45.498441136608358
], ],
[
-73.581414175680588,
45.498641136608358
],
[
-73.580914175680588,
45.498641136608358
],
[
-73.580914175680588,
45.499641136608358
],
[
-73.581914175680588,
45.499641136608358
],
[ [
-73.581914175680588, -73.581914175680588,
45.498441136608358 45.498441136608358
] ]
] ]
] ]
}, },

View File

@ -1 +1 @@
__version__ = '0.1.7.8' __version__ = '0.1.7.10'