2021-11-11 17:25:53 -05:00
|
|
|
"""
|
|
|
|
ComnetUsageParameters model the usage properties
|
|
|
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
|
|
Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
|
|
|
"""
|
|
|
|
import sys
|
|
|
|
from typing import Dict
|
|
|
|
import pandas as pd
|
|
|
|
|
|
|
|
import helpers.constants as cte
|
|
|
|
from helpers.configuration_helper import ConfigurationHelper as ch
|
|
|
|
from imports.geometry.helpers.geometry_helper import GeometryHelper
|
|
|
|
from imports.usage.helpers.usage_helper import UsageHelper
|
|
|
|
from city_model_structure.building_demand.usage_zone import UsageZone
|
2022-03-08 19:19:52 -05:00
|
|
|
from city_model_structure.building_demand.lighting import Lighting
|
|
|
|
from city_model_structure.building_demand.occupancy import Occupancy
|
|
|
|
from city_model_structure.building_demand.appliances import Appliances
|
2021-11-11 17:25:53 -05:00
|
|
|
from city_model_structure.building_demand.internal_gains import InternalGains
|
|
|
|
|
|
|
|
|
|
|
|
class ComnetUsageParameters:
|
|
|
|
"""
|
|
|
|
ComnetUsageParameters class
|
|
|
|
"""
|
|
|
|
def __init__(self, city, base_path):
|
|
|
|
self._city = city
|
|
|
|
self._base_path = str(base_path / 'comnet_archetypes.xlsx')
|
|
|
|
self._usage_archetypes = []
|
|
|
|
data = self._read_file()
|
|
|
|
for item in data['lighting']:
|
|
|
|
for usage in UsageHelper.usage_to_comnet:
|
|
|
|
comnet_usage = UsageHelper.usage_to_comnet[usage]
|
|
|
|
if comnet_usage == item:
|
|
|
|
usage_archetype = self._parse_zone_usage_type(comnet_usage, data)
|
|
|
|
self._usage_archetypes.append(usage_archetype)
|
|
|
|
|
|
|
|
def _read_file(self) -> Dict:
|
|
|
|
"""
|
|
|
|
reads xlsx file containing usage information into a dictionary
|
|
|
|
:return : Dict
|
|
|
|
"""
|
|
|
|
number_usage_types = 33
|
|
|
|
xl_file = pd.ExcelFile(self._base_path)
|
|
|
|
file_data = pd.read_excel(xl_file, sheet_name="Modeling Data", skiprows=[0, 1, 2],
|
|
|
|
nrows=number_usage_types, usecols="A:Z")
|
|
|
|
|
|
|
|
lighting_data = {}
|
|
|
|
plug_loads_data = {}
|
|
|
|
occupancy_data = {}
|
|
|
|
ventilation_rate = {}
|
|
|
|
water_heating = {}
|
|
|
|
process_data = {}
|
|
|
|
|
|
|
|
for j in range(0, number_usage_types):
|
|
|
|
usage_parameters = file_data.iloc[j]
|
|
|
|
usage_type = usage_parameters[0]
|
|
|
|
lighting_data[usage_type] = usage_parameters[1:6].values.tolist()
|
|
|
|
plug_loads_data[usage_type] = usage_parameters[8:13].values.tolist()
|
|
|
|
occupancy_data[usage_type] = usage_parameters[17:20].values.tolist()
|
|
|
|
ventilation_rate[usage_type] = usage_parameters[20:21].values.tolist()
|
|
|
|
water_heating[usage_type] = usage_parameters[23:24].values.tolist()
|
|
|
|
process_data[usage_type] = usage_parameters[24:26].values.tolist()
|
|
|
|
|
|
|
|
return {'lighting': lighting_data,
|
|
|
|
'plug loads': plug_loads_data,
|
|
|
|
'occupancy': occupancy_data,
|
|
|
|
'ventilation rate': ventilation_rate,
|
|
|
|
'water heating': water_heating,
|
|
|
|
'process': process_data}
|
|
|
|
|
|
|
|
@staticmethod
|
2022-03-08 19:19:52 -05:00
|
|
|
def _parse_zone_usage_type(usage, height, data):
|
|
|
|
_usage_zone = UsageZone()
|
|
|
|
_usage_zone.usage = usage
|
|
|
|
|
2021-11-11 17:25:53 -05:00
|
|
|
# lighting
|
2022-03-08 19:19:52 -05:00
|
|
|
_lighting = Lighting()
|
|
|
|
_lighting.latent_fraction = ch().comnet_lighting_latent
|
|
|
|
_lighting.convective_fraction = ch().comnet_lighting_convective
|
|
|
|
_lighting.radiative_fraction = ch().comnet_lighting_radiant
|
|
|
|
_lighting.average_internal_gain = data['lighting'][usage][4]
|
|
|
|
|
2021-11-11 17:25:53 -05:00
|
|
|
# plug loads
|
2022-03-08 19:19:52 -05:00
|
|
|
_appliances = None
|
2021-11-11 17:25:53 -05:00
|
|
|
if data['plug loads'][usage][0] != 'n.a.':
|
2022-03-08 19:19:52 -05:00
|
|
|
_appliances = Appliances()
|
|
|
|
_appliances.latent_fraction = ch().comnet_plugs_latent
|
|
|
|
_appliances.convective_fraction = ch().comnet_plugs_convective
|
|
|
|
_appliances.radiative_fraction = ch().comnet_plugs_radiant
|
|
|
|
_appliances.average_internal_gain = data['plug loads'][usage][0]
|
|
|
|
|
|
|
|
# occupancy
|
|
|
|
_occupancy = Occupancy()
|
|
|
|
_occupancy.occupancy_density = data['occupancy'][usage][0] * cte.METERS_TO_FEET**2
|
|
|
|
_occupancy.sensible_convective_internal_gain = data['occupancy'][usage][1] \
|
|
|
|
* ch().comnet_occupancy_sensible_convective
|
|
|
|
_occupancy.sensible_radiant_internal_gain = data['occupancy'][usage][1] * ch().comnet_occupancy_sensible_radiant
|
|
|
|
_occupancy.latent_internal_gain = data['occupancy'][usage][2]
|
|
|
|
|
|
|
|
if _occupancy.occupancy_density <= 0:
|
|
|
|
_usage_zone.mechanical_air_change = 0
|
|
|
|
else:
|
|
|
|
_usage_zone.mechanical_air_change = data['ventilation rate'][usage][0] / _occupancy.occupancy_density \
|
|
|
|
* cte.HOUR_TO_MINUTES / cte.METERS_TO_FEET**3 / height
|
|
|
|
|
|
|
|
_usage_zone.occupancy = _occupancy
|
|
|
|
_usage_zone.lighting = _lighting
|
|
|
|
_usage_zone.appliances = _appliances
|
|
|
|
return _usage_zone
|
2021-11-11 17:25:53 -05:00
|
|
|
|
|
|
|
def enrich_buildings(self):
|
|
|
|
"""
|
|
|
|
Returns the city with the usage parameters assigned to the buildings
|
|
|
|
:return:
|
|
|
|
"""
|
|
|
|
city = self._city
|
|
|
|
for building in city.buildings:
|
|
|
|
usage = GeometryHelper.usage_from_function(building.function)
|
|
|
|
height = building.average_storey_height
|
|
|
|
if height is None:
|
|
|
|
raise Exception('Average storey height not defined, ACH cannot be calculated')
|
|
|
|
if height <= 0:
|
|
|
|
raise Exception('Average storey height is zero, ACH cannot be calculated')
|
|
|
|
archetype = self._search_archetype(UsageHelper.comnet_from_usage(usage))
|
|
|
|
if archetype is None:
|
|
|
|
sys.stderr.write(f'Building {building.name} has unknown archetype for building function:'
|
|
|
|
f' {building.function}, that assigns building usage as '
|
|
|
|
f'{GeometryHelper.usage_from_function(building.function)}\n')
|
|
|
|
continue
|
|
|
|
|
|
|
|
# just one usage_zone
|
|
|
|
for thermal_zone in building.thermal_zones:
|
|
|
|
usage_zone = UsageZone()
|
|
|
|
usage_zone.usage = usage
|
|
|
|
self._assign_values(usage_zone, archetype, height)
|
|
|
|
usage_zone.volume = thermal_zone.volume
|
|
|
|
thermal_zone.usage_zones = [usage_zone]
|
|
|
|
|
|
|
|
def _search_archetype(self, building_usage):
|
|
|
|
for building_archetype in self._usage_archetypes:
|
|
|
|
if building_archetype.usage == building_usage:
|
|
|
|
return building_archetype
|
|
|
|
return None
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def _assign_values(usage_zone, archetype, height):
|
|
|
|
# Due to the fact that python is not a typed language, the wrong object type is assigned to
|
|
|
|
# usage_zone.internal_gains when writing usage_zone.internal_gains = archetype.internal_gains.
|
|
|
|
# Therefore, this walk around has been done.
|
|
|
|
internal_gains = []
|
|
|
|
for archetype_internal_gain in archetype.internal_gains:
|
|
|
|
internal_gain = InternalGains()
|
|
|
|
internal_gain.type = archetype_internal_gain.type
|
2022-03-08 19:19:52 -05:00
|
|
|
internal_gain.average_internal_gain = archetype_internal_gain.average_internal_gain
|
2021-11-11 17:25:53 -05:00
|
|
|
internal_gain.convective_fraction = archetype_internal_gain.convective_fraction
|
|
|
|
internal_gain.radiative_fraction = archetype_internal_gain.radiative_fraction
|
|
|
|
internal_gain.latent_fraction = archetype_internal_gain.latent_fraction
|
|
|
|
internal_gains.append(internal_gain)
|
|
|
|
usage_zone.internal_gains = internal_gains
|
2022-03-08 19:19:52 -05:00
|
|
|
usage_zone.occupancy_density = archetype.occupancy_density
|
|
|
|
usage_zone.mechanical_air_change = archetype.mechanical_air_change
|