forked from s_ranjbar/city_retrofit
added nrcan importer
usage importer now reads from catalogs
This commit is contained in:
parent
09bbe07ccb
commit
b34b07b161
|
@ -22,7 +22,7 @@ class Usage:
|
||||||
lighting,
|
lighting,
|
||||||
appliances,
|
appliances,
|
||||||
thermal_control):
|
thermal_control):
|
||||||
self._usage = usage
|
self._name = usage
|
||||||
self._hours_day = hours_day
|
self._hours_day = hours_day
|
||||||
self._days_year = days_year
|
self._days_year = days_year
|
||||||
self._mechanical_air_change = mechanical_air_change
|
self._mechanical_air_change = mechanical_air_change
|
||||||
|
@ -34,12 +34,12 @@ class Usage:
|
||||||
self._thermal_control = thermal_control
|
self._thermal_control = thermal_control
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def usage(self) -> Union[None, str]:
|
def name(self) -> Union[None, str]:
|
||||||
"""
|
"""
|
||||||
Get usage zone usage
|
Get usage zone usage name
|
||||||
:return: None or str
|
:return: None or str
|
||||||
"""
|
"""
|
||||||
return self._usage
|
return self._name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hours_day(self) -> Union[None, float]:
|
def hours_day(self) -> Union[None, float]:
|
||||||
|
|
|
@ -32,10 +32,6 @@ class NrcanCatalog(Catalog):
|
||||||
self._load_schedules()
|
self._load_schedules()
|
||||||
self._content = Content(self._load_archetypes())
|
self._content = Content(self._load_archetypes())
|
||||||
|
|
||||||
def _calculate_hours_day(self, function):
|
|
||||||
# todo: pilar need to check how to calculate this value
|
|
||||||
return 24
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _extract_schedule(raw):
|
def _extract_schedule(raw):
|
||||||
nrcan_schedule_type = raw['category']
|
nrcan_schedule_type = raw['category']
|
||||||
|
@ -69,8 +65,8 @@ class NrcanCatalog(Catalog):
|
||||||
|
|
||||||
def _load_archetypes(self):
|
def _load_archetypes(self):
|
||||||
usages = []
|
usages = []
|
||||||
usage = self._metadata['nrcan']['standards']['usage']
|
name = self._metadata['nrcan']['standards']['usage']
|
||||||
url = f'{self._base_url}{usage["space_types_location"]}'
|
url = f'{self._base_url}{name["space_types_location"]}'
|
||||||
with urllib.request.urlopen(url) as json_file:
|
with urllib.request.urlopen(url) as json_file:
|
||||||
space_types = json.load(json_file)['tables']['space_types']['table']
|
space_types = json.load(json_file)['tables']['space_types']['table']
|
||||||
space_types = [st for st in space_types if st['building_type'] == 'Space Function']
|
space_types = [st for st in space_types if st['building_type'] == 'Space Function']
|
||||||
|
@ -80,8 +76,6 @@ class NrcanCatalog(Catalog):
|
||||||
ventilation_rate = space_type['ventilation_per_area']
|
ventilation_rate = space_type['ventilation_per_area']
|
||||||
if ventilation_rate == 0:
|
if ventilation_rate == 0:
|
||||||
ventilation_rate = space_type['ventilation_per_person']
|
ventilation_rate = space_type['ventilation_per_person']
|
||||||
hours_day = self._calculate_hours_day(usage_type)
|
|
||||||
days_year = 365
|
|
||||||
occupancy_schedule_name = space_type['occupancy_schedule']
|
occupancy_schedule_name = space_type['occupancy_schedule']
|
||||||
lighting_schedule_name = space_type['lighting_schedule']
|
lighting_schedule_name = space_type['lighting_schedule']
|
||||||
appliance_schedule_name = space_type['electric_equipment_schedule']
|
appliance_schedule_name = space_type['electric_equipment_schedule']
|
||||||
|
@ -97,11 +91,13 @@ class NrcanCatalog(Catalog):
|
||||||
occupancy_density = space_type['occupancy_per_area']
|
occupancy_density = space_type['occupancy_per_area']
|
||||||
lighting_density = space_type['lighting_per_area']
|
lighting_density = space_type['lighting_per_area']
|
||||||
lighting_radiative_fraction = space_type['lighting_fraction_radiant']
|
lighting_radiative_fraction = space_type['lighting_fraction_radiant']
|
||||||
|
lighting_convective_fraction = 0
|
||||||
if lighting_radiative_fraction is not None:
|
if lighting_radiative_fraction is not None:
|
||||||
lighting_convective_fraction = 1 - lighting_radiative_fraction
|
lighting_convective_fraction = 1 - lighting_radiative_fraction
|
||||||
lighting_latent_fraction = 0
|
lighting_latent_fraction = 0
|
||||||
appliances_density = space_type['electric_equipment_per_area']
|
appliances_density = space_type['electric_equipment_per_area']
|
||||||
appliances_radiative_fraction = space_type['electric_equipment_fraction_radiant']
|
appliances_radiative_fraction = space_type['electric_equipment_fraction_radiant']
|
||||||
|
appliances_convective_fraction = 0
|
||||||
if appliances_radiative_fraction is not None:
|
if appliances_radiative_fraction is not None:
|
||||||
appliances_convective_fraction = 1 - appliances_radiative_fraction
|
appliances_convective_fraction = 1 - appliances_radiative_fraction
|
||||||
appliances_latent_fraction = space_type['electric_equipment_fraction_latent']
|
appliances_latent_fraction = space_type['electric_equipment_fraction_latent']
|
||||||
|
@ -131,6 +127,8 @@ class NrcanCatalog(Catalog):
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None)
|
None)
|
||||||
|
hours_day = None
|
||||||
|
days_year = None
|
||||||
usages.append(Usage(usage_type,
|
usages.append(Usage(usage_type,
|
||||||
hours_day,
|
hours_day,
|
||||||
days_year,
|
days_year,
|
||||||
|
@ -149,7 +147,7 @@ class NrcanCatalog(Catalog):
|
||||||
"""
|
"""
|
||||||
_names = {'usages': []}
|
_names = {'usages': []}
|
||||||
for usage in self._content.usages:
|
for usage in self._content.usages:
|
||||||
_names['usages'].append(usage.usage)
|
_names['usages'].append(usage.name)
|
||||||
return _names
|
return _names
|
||||||
|
|
||||||
def entries(self, category=None):
|
def entries(self, category=None):
|
||||||
|
@ -165,6 +163,6 @@ class NrcanCatalog(Catalog):
|
||||||
:parm: entry name
|
:parm: entry name
|
||||||
"""
|
"""
|
||||||
for usage in self._content.usages:
|
for usage in self._content.usages:
|
||||||
if usage.usage.lower() == name.lower():
|
if usage.name.lower() == name.lower():
|
||||||
return usage
|
return usage
|
||||||
raise IndexError(f"{name} doesn't exists in the catalog")
|
raise IndexError(f"{name} doesn't exists in the catalog")
|
||||||
|
|
|
@ -26,7 +26,7 @@ class ThermalZone:
|
||||||
"""
|
"""
|
||||||
ThermalZone class
|
ThermalZone class
|
||||||
"""
|
"""
|
||||||
def __init__(self, thermal_boundaries, parent_internal_zone, volume, footprint_area, usage=None):
|
def __init__(self, thermal_boundaries, parent_internal_zone, volume, footprint_area, usage_name=None):
|
||||||
self._id = None
|
self._id = None
|
||||||
self._parent_internal_zone = parent_internal_zone
|
self._parent_internal_zone = parent_internal_zone
|
||||||
self._footprint_area = footprint_area
|
self._footprint_area = footprint_area
|
||||||
|
@ -40,9 +40,9 @@ class ThermalZone:
|
||||||
self._ordinate_number = None
|
self._ordinate_number = None
|
||||||
self._view_factors_matrix = None
|
self._view_factors_matrix = None
|
||||||
self._total_floor_area = None
|
self._total_floor_area = None
|
||||||
self._usage = usage
|
self._usage_name = usage_name
|
||||||
self._usage_from_parent = False
|
self._usage_from_parent = False
|
||||||
if usage is None:
|
if usage_name is None:
|
||||||
self._usage_from_parent = True
|
self._usage_from_parent = True
|
||||||
self._hours_day = None
|
self._hours_day = None
|
||||||
self._days_year = None
|
self._days_year = None
|
||||||
|
@ -60,14 +60,14 @@ class ThermalZone:
|
||||||
if self._usage_from_parent:
|
if self._usage_from_parent:
|
||||||
self._usages = copy.deepcopy(self._parent_internal_zone.usages)
|
self._usages = copy.deepcopy(self._parent_internal_zone.usages)
|
||||||
else:
|
else:
|
||||||
values = self._usage.split('_')
|
values = self._usage_name.split('_')
|
||||||
usages = []
|
usages = []
|
||||||
for value in values:
|
for value in values:
|
||||||
usages.append(value.split('-'))
|
usages.append(value.split('-'))
|
||||||
self._usages = []
|
self._usages = []
|
||||||
for parent_usage in self._parent_internal_zone.usages:
|
for parent_usage in self._parent_internal_zone.usages:
|
||||||
for value in usages:
|
for value in usages:
|
||||||
if parent_usage.usage == value[1]:
|
if parent_usage.name == value[1]:
|
||||||
new_usage = copy.deepcopy(parent_usage)
|
new_usage = copy.deepcopy(parent_usage)
|
||||||
new_usage.percentage = float(value[0])/100
|
new_usage.percentage = float(value[0])/100
|
||||||
self._usages.append(new_usage)
|
self._usages.append(new_usage)
|
||||||
|
@ -224,19 +224,19 @@ class ThermalZone:
|
||||||
self._view_factors_matrix = value
|
self._view_factors_matrix = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def usage(self) -> Union[None, str]:
|
def usage_name(self) -> Union[None, str]:
|
||||||
"""
|
"""
|
||||||
Get thermal zone usage
|
Get thermal zone usage name
|
||||||
:return: None or str
|
:return: None or str
|
||||||
"""
|
"""
|
||||||
if self._usage_from_parent:
|
if self._usage_from_parent:
|
||||||
if self._parent_internal_zone.usages is None:
|
if self._parent_internal_zone.usages is None:
|
||||||
return None
|
return None
|
||||||
self._usage = ''
|
self._usage_name = ''
|
||||||
for usage_zone in self._parent_internal_zone.usages:
|
for usage_zone in self._parent_internal_zone.usages:
|
||||||
self._usage += str(round(usage_zone.percentage * 100)) + '-' + usage_zone.name + '_'
|
self._usage_name += str(round(usage_zone.percentage * 100)) + '-' + usage_zone.name + '_'
|
||||||
self._usage = self._usage[:-1]
|
self._usage_name = self._usage_name[:-1]
|
||||||
return self._usage
|
return self._usage_name
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_schedule_of_day(requested_day_type, schedules):
|
def _get_schedule_of_day(requested_day_type, schedules):
|
||||||
|
@ -322,7 +322,13 @@ class ThermalZone:
|
||||||
if _occupancy_reference.occupancy_schedules is not None:
|
if _occupancy_reference.occupancy_schedules is not None:
|
||||||
_schedules = []
|
_schedules = []
|
||||||
for i_schedule in range(0, len(_occupancy_reference.occupancy_schedules)):
|
for i_schedule in range(0, len(_occupancy_reference.occupancy_schedules)):
|
||||||
schedule = copy.deepcopy(_occupancy_reference.occupancy_schedules[i_schedule])
|
schedule = Schedule()
|
||||||
|
schedule.type = _occupancy_reference.occupancy_schedules[i_schedule].type
|
||||||
|
schedule.day_types = _occupancy_reference.occupancy_schedules[i_schedule].day_types
|
||||||
|
schedule.data_type = _occupancy_reference.occupancy_schedules[i_schedule].data_type
|
||||||
|
schedule.time_step = _occupancy_reference.occupancy_schedules[i_schedule].time_step
|
||||||
|
schedule.time_range = _occupancy_reference.occupancy_schedules[i_schedule].time_range
|
||||||
|
|
||||||
new_values = []
|
new_values = []
|
||||||
for i_value in range(0, len(_occupancy_reference.occupancy_schedules[i_schedule].values)):
|
for i_value in range(0, len(_occupancy_reference.occupancy_schedules[i_schedule].values)):
|
||||||
_new_value = 0
|
_new_value = 0
|
||||||
|
@ -374,7 +380,13 @@ class ThermalZone:
|
||||||
if _lighting_reference.schedules is not None:
|
if _lighting_reference.schedules is not None:
|
||||||
_schedules = []
|
_schedules = []
|
||||||
for i_schedule in range(0, len(_lighting_reference.schedules)):
|
for i_schedule in range(0, len(_lighting_reference.schedules)):
|
||||||
schedule = copy.deepcopy(_lighting_reference.schedules[i_schedule])
|
schedule = Schedule()
|
||||||
|
schedule.type = _lighting_reference.schedules[i_schedule].type
|
||||||
|
schedule.day_types = _lighting_reference.schedules[i_schedule].day_types
|
||||||
|
schedule.data_type = _lighting_reference.schedules[i_schedule].data_type
|
||||||
|
schedule.time_step = _lighting_reference.schedules[i_schedule].time_step
|
||||||
|
schedule.time_range = _lighting_reference.schedules[i_schedule].time_range
|
||||||
|
|
||||||
new_values = []
|
new_values = []
|
||||||
for i_value in range(0, len(_lighting_reference.schedules[i_schedule].values)):
|
for i_value in range(0, len(_lighting_reference.schedules[i_schedule].values)):
|
||||||
_new_value = 0
|
_new_value = 0
|
||||||
|
@ -426,7 +438,13 @@ class ThermalZone:
|
||||||
if _appliances_reference.schedules is not None:
|
if _appliances_reference.schedules is not None:
|
||||||
_schedules = []
|
_schedules = []
|
||||||
for i_schedule in range(0, len(_appliances_reference.schedules)):
|
for i_schedule in range(0, len(_appliances_reference.schedules)):
|
||||||
schedule = copy.deepcopy(_appliances_reference.schedules[i_schedule])
|
schedule = Schedule()
|
||||||
|
schedule.type = _appliances_reference.schedules[i_schedule].type
|
||||||
|
schedule.day_types = _appliances_reference.schedules[i_schedule].day_types
|
||||||
|
schedule.data_type = _appliances_reference.schedules[i_schedule].data_type
|
||||||
|
schedule.time_step = _appliances_reference.schedules[i_schedule].time_step
|
||||||
|
schedule.time_range = _appliances_reference.schedules[i_schedule].time_range
|
||||||
|
|
||||||
new_values = []
|
new_values = []
|
||||||
for i_value in range(0, len(_appliances_reference.schedules[i_schedule].values)):
|
for i_value in range(0, len(_appliances_reference.schedules[i_schedule].values)):
|
||||||
_new_value = 0
|
_new_value = 0
|
||||||
|
@ -535,7 +553,13 @@ class ThermalZone:
|
||||||
_schedules = []
|
_schedules = []
|
||||||
_schedule_type = _types_reference[i_type][1]
|
_schedule_type = _types_reference[i_type][1]
|
||||||
for i_schedule in range(0, len(_schedule_type)):
|
for i_schedule in range(0, len(_schedule_type)):
|
||||||
schedule = copy.deepcopy(_schedule_type[i_schedule])
|
schedule = Schedule()
|
||||||
|
schedule.type = _schedule_type[i_schedule].type
|
||||||
|
schedule.day_types = _schedule_type[i_schedule].day_types
|
||||||
|
schedule.data_type = _schedule_type[i_schedule].data_type
|
||||||
|
schedule.time_step = _schedule_type[i_schedule].time_step
|
||||||
|
schedule.time_range = _schedule_type[i_schedule].time_range
|
||||||
|
|
||||||
new_values = []
|
new_values = []
|
||||||
for i_value in range(0, len(_schedule_type[i_schedule].values)):
|
for i_value in range(0, len(_schedule_type[i_schedule].values)):
|
||||||
_new_value = 0
|
_new_value = 0
|
||||||
|
|
|
@ -207,9 +207,9 @@ class Idf:
|
||||||
_schedule.values = _infiltration_values
|
_schedule.values = _infiltration_values
|
||||||
_infiltration_schedules.append(_schedule)
|
_infiltration_schedules.append(_schedule)
|
||||||
for schedule in self._idf.idfobjects[self._HOURLY_SCHEDULE]:
|
for schedule in self._idf.idfobjects[self._HOURLY_SCHEDULE]:
|
||||||
if schedule.Name == f'Infiltration schedules {thermal_zone.usage}':
|
if schedule.Name == f'Infiltration schedules {thermal_zone.usage_name}':
|
||||||
return
|
return
|
||||||
return self._add_standard_compact_hourly_schedule(thermal_zone.usage, 'Infiltration', _infiltration_schedules)
|
return self._add_standard_compact_hourly_schedule(thermal_zone.usage_name, 'Infiltration', _infiltration_schedules)
|
||||||
|
|
||||||
def _add_people_activity_level_schedules(self, thermal_zone):
|
def _add_people_activity_level_schedules(self, thermal_zone):
|
||||||
_occ = thermal_zone.occupancy
|
_occ = thermal_zone.occupancy
|
||||||
|
@ -219,9 +219,9 @@ class Idf:
|
||||||
_total_heat = (_occ.sensible_convective_internal_gain + _occ.sensible_radiative_internal_gain
|
_total_heat = (_occ.sensible_convective_internal_gain + _occ.sensible_radiative_internal_gain
|
||||||
+ _occ.latent_internal_gain) / _occ.occupancy_density
|
+ _occ.latent_internal_gain) / _occ.occupancy_density
|
||||||
for schedule in self._idf.idfobjects[self._COMPACT_SCHEDULE]:
|
for schedule in self._idf.idfobjects[self._COMPACT_SCHEDULE]:
|
||||||
if schedule.Name == f'Activity Level schedules {thermal_zone.usage}':
|
if schedule.Name == f'Activity Level schedules {thermal_zone.usage_name}':
|
||||||
return
|
return
|
||||||
_kwargs = {'Name': f'Activity Level schedules {thermal_zone.usage}',
|
_kwargs = {'Name': f'Activity Level schedules {thermal_zone.usage_name}',
|
||||||
'Schedule_Type_Limits_Name': self.idf_type_limits[cte.ANY_NUMBER],
|
'Schedule_Type_Limits_Name': self.idf_type_limits[cte.ANY_NUMBER],
|
||||||
'Field_1': 'Through: 12/31',
|
'Field_1': 'Through: 12/31',
|
||||||
'Field_2': 'For AllDays',
|
'Field_2': 'For AllDays',
|
||||||
|
@ -300,15 +300,15 @@ class Idf:
|
||||||
self._add_heating_system(thermal_zone, name)
|
self._add_heating_system(thermal_zone, name)
|
||||||
|
|
||||||
def _add_thermostat(self, thermal_zone):
|
def _add_thermostat(self, thermal_zone):
|
||||||
thermostat_name = f'Thermostat {thermal_zone.usage}'
|
thermostat_name = f'Thermostat {thermal_zone.usage_name}'
|
||||||
for thermostat in self._idf.idfobjects[self._THERMOSTAT]:
|
for thermostat in self._idf.idfobjects[self._THERMOSTAT]:
|
||||||
if thermostat.Name == thermostat_name:
|
if thermostat.Name == thermostat_name:
|
||||||
return thermostat
|
return thermostat
|
||||||
# todo: change schedules to schedule name and create schedules using the add_schedule function
|
# todo: change schedules to schedule name and create schedules using the add_schedule function
|
||||||
return self._idf.newidfobject(self._THERMOSTAT,
|
return self._idf.newidfobject(self._THERMOSTAT,
|
||||||
Name=thermostat_name,
|
Name=thermostat_name,
|
||||||
Heating_Setpoint_Schedule_Name=f'Heating thermostat schedules {thermal_zone.usage}',
|
Heating_Setpoint_Schedule_Name=f'Heating thermostat schedules {thermal_zone.usage_name}',
|
||||||
Cooling_Setpoint_Schedule_Name=f'Cooling thermostat schedules {thermal_zone.usage}')
|
Cooling_Setpoint_Schedule_Name=f'Cooling thermostat schedules {thermal_zone.usage_name}')
|
||||||
|
|
||||||
def _add_heating_system(self, thermal_zone, zone_name):
|
def _add_heating_system(self, thermal_zone, zone_name):
|
||||||
for air_system in self._idf.idfobjects[self._IDEAL_LOAD_AIR_SYSTEM]:
|
for air_system in self._idf.idfobjects[self._IDEAL_LOAD_AIR_SYSTEM]:
|
||||||
|
@ -317,9 +317,9 @@ class Idf:
|
||||||
thermostat = self._add_thermostat(thermal_zone)
|
thermostat = self._add_thermostat(thermal_zone)
|
||||||
self._idf.newidfobject(self._IDEAL_LOAD_AIR_SYSTEM,
|
self._idf.newidfobject(self._IDEAL_LOAD_AIR_SYSTEM,
|
||||||
Zone_Name=zone_name,
|
Zone_Name=zone_name,
|
||||||
System_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage}',
|
System_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage_name}',
|
||||||
Heating_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage}',
|
Heating_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage_name}',
|
||||||
Cooling_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage}',
|
Cooling_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage_name}',
|
||||||
Template_Thermostat_Name=thermostat.Name)
|
Template_Thermostat_Name=thermostat.Name)
|
||||||
|
|
||||||
def _add_occupancy(self, thermal_zone, zone_name):
|
def _add_occupancy(self, thermal_zone, zone_name):
|
||||||
|
@ -330,11 +330,11 @@ class Idf:
|
||||||
self._idf.newidfobject(self._PEOPLE,
|
self._idf.newidfobject(self._PEOPLE,
|
||||||
Name=f'{zone_name}_occupancy',
|
Name=f'{zone_name}_occupancy',
|
||||||
Zone_or_ZoneList_Name=zone_name,
|
Zone_or_ZoneList_Name=zone_name,
|
||||||
Number_of_People_Schedule_Name=f'Occupancy schedules {thermal_zone.usage}',
|
Number_of_People_Schedule_Name=f'Occupancy schedules {thermal_zone.usage_name}',
|
||||||
Number_of_People_Calculation_Method="People",
|
Number_of_People_Calculation_Method="People",
|
||||||
Number_of_People=number_of_people,
|
Number_of_People=number_of_people,
|
||||||
Fraction_Radiant=fraction_radiant,
|
Fraction_Radiant=fraction_radiant,
|
||||||
Activity_Level_Schedule_Name=f'Activity Level schedules {thermal_zone.usage}'
|
Activity_Level_Schedule_Name=f'Activity Level schedules {thermal_zone.usage_name}'
|
||||||
)
|
)
|
||||||
|
|
||||||
def _add_infiltration(self, thermal_zone, zone_name):
|
def _add_infiltration(self, thermal_zone, zone_name):
|
||||||
|
@ -344,7 +344,7 @@ class Idf:
|
||||||
self._idf.newidfobject(self._INFILTRATION,
|
self._idf.newidfobject(self._INFILTRATION,
|
||||||
Name=f'{zone_name}_infiltration',
|
Name=f'{zone_name}_infiltration',
|
||||||
Zone_or_ZoneList_Name=zone_name,
|
Zone_or_ZoneList_Name=zone_name,
|
||||||
Schedule_Name=f'Infiltration schedules {thermal_zone.usage}',
|
Schedule_Name=f'Infiltration schedules {thermal_zone.usage_name}',
|
||||||
Design_Flow_Rate_Calculation_Method='AirChanges/Hour',
|
Design_Flow_Rate_Calculation_Method='AirChanges/Hour',
|
||||||
Air_Changes_per_Hour=thermal_zone.mechanical_air_change
|
Air_Changes_per_Hour=thermal_zone.mechanical_air_change
|
||||||
)
|
)
|
||||||
|
@ -387,7 +387,7 @@ class Idf:
|
||||||
self._add_vegetation_material(thermal_boundary.parent_surface.vegetation)
|
self._add_vegetation_material(thermal_boundary.parent_surface.vegetation)
|
||||||
for thermal_opening in thermal_boundary.thermal_openings:
|
for thermal_opening in thermal_boundary.thermal_openings:
|
||||||
self._add_window_construction_and_material(thermal_opening)
|
self._add_window_construction_and_material(thermal_opening)
|
||||||
usage = thermal_zone.usage
|
usage = thermal_zone.usage_name
|
||||||
if building.name in self._target_buildings or building.name in self._adjacent_buildings:
|
if building.name in self._target_buildings or building.name in self._adjacent_buildings:
|
||||||
self._add_infiltration_schedules(thermal_zone)
|
self._add_infiltration_schedules(thermal_zone)
|
||||||
self._add_schedules(usage, 'Occupancy', thermal_zone.occupancy.occupancy_schedules)
|
self._add_schedules(usage, 'Occupancy', thermal_zone.occupancy.occupancy_schedules)
|
||||||
|
|
|
@ -29,12 +29,14 @@ class NrelPhysicsParameters:
|
||||||
Returns the city with the construction parameters assigned to the buildings
|
Returns the city with the construction parameters assigned to the buildings
|
||||||
"""
|
"""
|
||||||
city = self._city
|
city = self._city
|
||||||
|
nrel_catalog = ConstructionCatalogFactory('nrel').catalog
|
||||||
for building in city.buildings:
|
for building in city.buildings:
|
||||||
try:
|
try:
|
||||||
archetype = self._search_archetype(building.function, building.year_of_construction, self._climate_zone)
|
archetype = self._search_archetype(nrel_catalog, building.function, building.year_of_construction,
|
||||||
|
self._climate_zone)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
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
|
return
|
||||||
|
|
||||||
|
@ -62,8 +64,7 @@ class NrelPhysicsParameters:
|
||||||
self._calculate_view_factors(thermal_zone)
|
self._calculate_view_factors(thermal_zone)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _search_archetype(function, year_of_construction, climate_zone):
|
def _search_archetype(nrel_catalog, function, year_of_construction, climate_zone):
|
||||||
nrel_catalog = ConstructionCatalogFactory('nrel').catalog
|
|
||||||
nrel_archetypes = nrel_catalog.entries('archetypes')
|
nrel_archetypes = nrel_catalog.entries('archetypes')
|
||||||
for building_archetype in nrel_archetypes:
|
for building_archetype in nrel_archetypes:
|
||||||
construction_period_limits = building_archetype.construction_period.split(' - ')
|
construction_period_limits = building_archetype.construction_period.split(' - ')
|
||||||
|
|
|
@ -1,20 +1,15 @@
|
||||||
"""
|
"""
|
||||||
ComnetUsageParameters model the usage properties
|
ComnetUsageParameters extracts the usage properties from Comnet catalog and assigns to each building
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2022 Concordia CERC group
|
Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
"""
|
"""
|
||||||
import copy
|
import copy
|
||||||
import sys
|
import sys
|
||||||
from typing import Dict
|
|
||||||
import pandas as pd
|
|
||||||
import numpy
|
import numpy
|
||||||
|
|
||||||
import helpers.constants as cte
|
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 imports.usage.helpers.usage_helper import UsageHelper
|
||||||
from imports.usage.helpers.schedules_helper import SchedulesHelper
|
|
||||||
from city_model_structure.building_demand.usage import Usage
|
from city_model_structure.building_demand.usage import Usage
|
||||||
from city_model_structure.building_demand.lighting import Lighting
|
from city_model_structure.building_demand.lighting import Lighting
|
||||||
from city_model_structure.building_demand.occupancy import Occupancy
|
from city_model_structure.building_demand.occupancy import Occupancy
|
||||||
|
@ -22,6 +17,7 @@ from city_model_structure.building_demand.appliances import Appliances
|
||||||
from city_model_structure.building_demand.thermal_control import ThermalControl
|
from city_model_structure.building_demand.thermal_control import ThermalControl
|
||||||
from city_model_structure.attributes.schedule import Schedule
|
from city_model_structure.attributes.schedule import Schedule
|
||||||
from city_model_structure.building_demand.internal_gain import InternalGain
|
from city_model_structure.building_demand.internal_gain import InternalGain
|
||||||
|
from catalog_factories.usage_catalog_factory import UsageCatalogFactory
|
||||||
|
|
||||||
|
|
||||||
class ComnetUsageParameters:
|
class ComnetUsageParameters:
|
||||||
|
@ -30,162 +26,7 @@ class ComnetUsageParameters:
|
||||||
"""
|
"""
|
||||||
def __init__(self, city, base_path):
|
def __init__(self, city, base_path):
|
||||||
self._city = city
|
self._city = city
|
||||||
self._base_path = str(base_path / 'comnet_archetypes.xlsx')
|
self._path = base_path
|
||||||
self._data = self._read_file()
|
|
||||||
self._comnet_schedules_path = str(base_path / 'comnet_schedules_archetypes.xlsx')
|
|
||||||
self._xls = pd.ExcelFile(self._comnet_schedules_path)
|
|
||||||
|
|
||||||
def _read_file(self) -> Dict:
|
|
||||||
"""
|
|
||||||
reads xlsx files 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", usecols="A:AB", skiprows=[0, 1, 2],
|
|
||||||
nrows=number_usage_types)
|
|
||||||
|
|
||||||
lighting_data = {}
|
|
||||||
plug_loads_data = {}
|
|
||||||
occupancy_data = {}
|
|
||||||
ventilation_rate = {}
|
|
||||||
water_heating = {}
|
|
||||||
process_data = {}
|
|
||||||
schedules_key = {}
|
|
||||||
|
|
||||||
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()
|
|
||||||
schedules_key[usage_type] = usage_parameters[27:28].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,
|
|
||||||
'schedules_key': schedules_key}
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _parse_usage_type(comnet_usage, data, schedules_data):
|
|
||||||
_usage = Usage()
|
|
||||||
|
|
||||||
# lighting
|
|
||||||
_lighting = Lighting()
|
|
||||||
_lighting.latent_fraction = ch().comnet_lighting_latent
|
|
||||||
_lighting.convective_fraction = ch().comnet_lighting_convective
|
|
||||||
_lighting.radiative_fraction = ch().comnet_lighting_radiant
|
|
||||||
_lighting.density = data['lighting'][comnet_usage][4]
|
|
||||||
|
|
||||||
# plug loads
|
|
||||||
_appliances = None
|
|
||||||
if data['plug loads'][comnet_usage][0] != 'n.a.':
|
|
||||||
_appliances = Appliances()
|
|
||||||
_appliances.latent_fraction = ch().comnet_plugs_latent
|
|
||||||
_appliances.convective_fraction = ch().comnet_plugs_convective
|
|
||||||
_appliances.radiative_fraction = ch().comnet_plugs_radiant
|
|
||||||
_appliances.density = data['plug loads'][comnet_usage][0]
|
|
||||||
|
|
||||||
# occupancy
|
|
||||||
_occupancy = Occupancy()
|
|
||||||
value = data['occupancy'][comnet_usage][0]
|
|
||||||
_occupancy.occupancy_density = 0
|
|
||||||
if value != 0:
|
|
||||||
_occupancy.occupancy_density = 1 / value
|
|
||||||
|
|
||||||
_occupancy.sensible_convective_internal_gain = data['occupancy'][comnet_usage][1] \
|
|
||||||
* ch().comnet_occupancy_sensible_convective
|
|
||||||
_occupancy.sensible_radiative_internal_gain = data['occupancy'][comnet_usage][1] \
|
|
||||||
* ch().comnet_occupancy_sensible_radiant
|
|
||||||
_occupancy.latent_internal_gain = data['occupancy'][comnet_usage][2]
|
|
||||||
|
|
||||||
_usage.mechanical_air_change = data['ventilation rate'][comnet_usage][0]
|
|
||||||
|
|
||||||
schedules_usage = UsageHelper.schedules_key(data['schedules_key'][comnet_usage][0])
|
|
||||||
|
|
||||||
_extracted_data = pd.read_excel(schedules_data, sheet_name=schedules_usage, usecols="A:AA", skiprows=[0, 1, 2, 3],
|
|
||||||
nrows=39)
|
|
||||||
schedules = []
|
|
||||||
number_of_schedule_types = 13
|
|
||||||
schedules_per_schedule_type = 3
|
|
||||||
day_types = dict({'week_day': 0, 'saturday': 1, 'sunday': 2})
|
|
||||||
for schedule_types in range(0, number_of_schedule_types):
|
|
||||||
name = ''
|
|
||||||
data_type = ''
|
|
||||||
for schedule_day in range(0, schedules_per_schedule_type):
|
|
||||||
_schedule = Schedule()
|
|
||||||
_schedule.time_step = cte.HOUR
|
|
||||||
_schedule.time_range = cte.DAY
|
|
||||||
row_cells = _extracted_data.iloc[schedules_per_schedule_type * schedule_types + schedule_day]
|
|
||||||
if schedule_day == day_types['week_day']:
|
|
||||||
name = row_cells[0]
|
|
||||||
data_type = row_cells[1]
|
|
||||||
_schedule.day_types = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY]
|
|
||||||
elif schedule_day == day_types['saturday']:
|
|
||||||
_schedule.day_types = [cte.SATURDAY]
|
|
||||||
else:
|
|
||||||
_schedule.day_types = [cte.SUNDAY, cte.HOLIDAY]
|
|
||||||
_schedule.type = name
|
|
||||||
_schedule.data_type = SchedulesHelper.data_type_from_comnet(data_type)
|
|
||||||
if _schedule.data_type == cte.ANY_NUMBER:
|
|
||||||
values = []
|
|
||||||
for cell in row_cells[schedules_per_schedule_type:].to_numpy():
|
|
||||||
values.append((float(cell) - 32.) * 5 / 9)
|
|
||||||
_schedule.values = values
|
|
||||||
else:
|
|
||||||
_schedule.values = row_cells[schedules_per_schedule_type:].to_numpy()
|
|
||||||
schedules.append(_schedule)
|
|
||||||
|
|
||||||
schedules_types = dict({'Occupancy': 0, 'Lights': 3, 'Receptacle': 6, 'Infiltration': 9, 'HVAC Avail': 12,
|
|
||||||
'ClgSetPt': 15, 'HtgSetPt': 18})
|
|
||||||
|
|
||||||
_schedules = []
|
|
||||||
for pointer in range(0, 3):
|
|
||||||
_schedules.append(schedules[schedules_types['Occupancy']+pointer])
|
|
||||||
_occupancy.occupancy_schedules = _schedules
|
|
||||||
_schedules = []
|
|
||||||
for pointer in range(0, 3):
|
|
||||||
_schedules.append(schedules[schedules_types['Lights']+pointer])
|
|
||||||
_lighting.schedules = _schedules
|
|
||||||
_schedules = []
|
|
||||||
for pointer in range(0, 3):
|
|
||||||
_schedules.append(schedules[schedules_types['Receptacle']+pointer])
|
|
||||||
_appliances.schedules = _schedules
|
|
||||||
|
|
||||||
_usage.occupancy = _occupancy
|
|
||||||
_usage.lighting = _lighting
|
|
||||||
_usage.appliances = _appliances
|
|
||||||
|
|
||||||
_control = ThermalControl()
|
|
||||||
_schedules = []
|
|
||||||
for pointer in range(0, 3):
|
|
||||||
_schedules.append(schedules[schedules_types['HtgSetPt']+pointer])
|
|
||||||
_control.heating_set_point_schedules = _schedules
|
|
||||||
_schedules = []
|
|
||||||
for pointer in range(0, 3):
|
|
||||||
_schedules.append(schedules[schedules_types['ClgSetPt']+pointer])
|
|
||||||
_control.cooling_set_point_schedules = _schedules
|
|
||||||
_schedules = []
|
|
||||||
for pointer in range(0, 3):
|
|
||||||
_schedules.append(schedules[schedules_types['HVAC Avail']+pointer])
|
|
||||||
_control.hvac_availability_schedules = _schedules
|
|
||||||
_usage.thermal_control = _control
|
|
||||||
|
|
||||||
return _usage
|
|
||||||
|
|
||||||
def _search_archetypes(self, libs_usage):
|
|
||||||
for item in self._data['lighting']:
|
|
||||||
comnet_usage = UsageHelper.comnet_from_libs_usage(libs_usage)
|
|
||||||
if comnet_usage == item:
|
|
||||||
usage_archetype = self._parse_usage_type(comnet_usage, self._data, self._xls)
|
|
||||||
return usage_archetype
|
|
||||||
return None
|
|
||||||
|
|
||||||
def enrich_buildings(self):
|
def enrich_buildings(self):
|
||||||
"""
|
"""
|
||||||
|
@ -193,14 +34,14 @@ class ComnetUsageParameters:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
city = self._city
|
city = self._city
|
||||||
|
comnet_catalog = UsageCatalogFactory('comnet').catalog
|
||||||
for building in city.buildings:
|
for building in city.buildings:
|
||||||
usage = GeometryHelper.libs_usage_from_libs_function(building.function)
|
usage_name = UsageHelper.comnet_from_hub_usage(building.function)
|
||||||
try:
|
try:
|
||||||
archetype_usage = self._search_archetypes(usage)
|
archetype_usage = self._search_archetypes(comnet_catalog, usage_name)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
sys.stderr.write(f'Building {building.name} has unknown archetype for building function:'
|
sys.stderr.write(f'Building {building.name} has unknown usage archetype for building function:'
|
||||||
f' {building.function}, that assigns building usage as '
|
f' {building.function}')
|
||||||
f'{GeometryHelper.libs_usage_from_libs_function(building.function)}\n')
|
|
||||||
return
|
return
|
||||||
|
|
||||||
for internal_zone in building.internal_zones:
|
for internal_zone in building.internal_zones:
|
||||||
|
@ -210,46 +51,46 @@ class ComnetUsageParameters:
|
||||||
raise Exception('Internal zone volume not defined, ACH cannot be calculated')
|
raise Exception('Internal zone volume not defined, ACH cannot be calculated')
|
||||||
if internal_zone.area <= 0:
|
if internal_zone.area <= 0:
|
||||||
raise Exception('Internal zone area is zero, ACH cannot be calculated')
|
raise Exception('Internal zone area is zero, ACH cannot be calculated')
|
||||||
if internal_zone.volume <= 0:
|
|
||||||
raise Exception('Internal zone volume is zero, ACH cannot be calculated')
|
|
||||||
volume_per_area = internal_zone.volume / internal_zone.area
|
volume_per_area = internal_zone.volume / internal_zone.area
|
||||||
usage_zone = Usage()
|
usage_zone = Usage()
|
||||||
usage_zone.name = usage
|
usage_zone.name = usage_name
|
||||||
self._assign_values_usage_zone(usage_zone, archetype_usage, volume_per_area)
|
self._assign_values(usage_zone, archetype_usage, volume_per_area)
|
||||||
usage_zone.percentage = 1
|
usage_zone.percentage = 1
|
||||||
self._calculate_reduced_values_from_extended_library(usage_zone, archetype_usage)
|
self._calculate_reduced_values_from_extended_library(usage_zone, archetype_usage)
|
||||||
|
|
||||||
internal_zone.usages = [usage_zone]
|
internal_zone.usages = [usage_zone]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _assign_values_usage_zone(usage_zone, archetype, volume_per_area):
|
def _search_archetypes(comnet_catalog, usage_name):
|
||||||
|
comnet_archetypes = comnet_catalog.entries('archetypes').usages
|
||||||
|
for building_archetype in comnet_archetypes:
|
||||||
|
if str(usage_name) == str(building_archetype.name):
|
||||||
|
return building_archetype
|
||||||
|
raise KeyError('archetype not found')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _assign_values(usage_zone, archetype, volume_per_area):
|
||||||
# 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_zone.occupancy when writing usage_zone.occupancy = archetype.occupancy.
|
# usage_zone.occupancy when writing usage_zone.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.
|
||||||
usage_zone.mechanical_air_change = archetype.mechanical_air_change * cte.METERS_TO_FEET ** 2 \
|
usage_zone.mechanical_air_change = archetype.ventilation_rate / volume_per_area \
|
||||||
* cte.HOUR_TO_MINUTES / cte.METERS_TO_FEET ** 3 / volume_per_area
|
* cte.HOUR_TO_MINUTES * cte.MINUTES_TO_SECONDS
|
||||||
_occupancy = Occupancy()
|
_occupancy = Occupancy()
|
||||||
_occupancy.occupancy_density = archetype.occupancy.occupancy_density * cte.METERS_TO_FEET**2
|
_occupancy.occupancy_density = archetype.occupancy.occupancy_density
|
||||||
_occupancy.sensible_radiative_internal_gain = archetype.occupancy.sensible_radiative_internal_gain \
|
_occupancy.sensible_radiative_internal_gain = archetype.occupancy.sensible_radiative_internal_gain
|
||||||
* archetype.occupancy.occupancy_density \
|
_occupancy.latent_internal_gain = archetype.occupancy.latent_internal_gain
|
||||||
* cte.METERS_TO_FEET**2 * cte.BTU_H_TO_WATTS
|
_occupancy.sensible_convective_internal_gain = archetype.occupancy.sensible_convective_internal_gain
|
||||||
_occupancy.latent_internal_gain = archetype.occupancy.latent_internal_gain \
|
_occupancy.occupancy_schedules = archetype.occupancy.schedules
|
||||||
* archetype.occupancy.occupancy_density \
|
|
||||||
* cte.METERS_TO_FEET**2 * cte.BTU_H_TO_WATTS
|
|
||||||
_occupancy.sensible_convective_internal_gain = archetype.occupancy.sensible_convective_internal_gain \
|
|
||||||
* archetype.occupancy.occupancy_density \
|
|
||||||
* cte.METERS_TO_FEET**2 * cte.BTU_H_TO_WATTS
|
|
||||||
_occupancy.occupancy_schedules = archetype.occupancy.occupancy_schedules
|
|
||||||
usage_zone.occupancy = _occupancy
|
usage_zone.occupancy = _occupancy
|
||||||
_lighting = Lighting()
|
_lighting = Lighting()
|
||||||
_lighting.density = archetype.lighting.density / cte.METERS_TO_FEET ** 2
|
_lighting.density = archetype.lighting.density
|
||||||
_lighting.convective_fraction = archetype.lighting.convective_fraction
|
_lighting.convective_fraction = archetype.lighting.convective_fraction
|
||||||
_lighting.radiative_fraction = archetype.lighting.radiative_fraction
|
_lighting.radiative_fraction = archetype.lighting.radiative_fraction
|
||||||
_lighting.latent_fraction = archetype.lighting.latent_fraction
|
_lighting.latent_fraction = archetype.lighting.latent_fraction
|
||||||
_lighting.schedules = archetype.lighting.schedules
|
_lighting.schedules = archetype.lighting.schedules
|
||||||
usage_zone.lighting = _lighting
|
usage_zone.lighting = _lighting
|
||||||
_appliances = Appliances()
|
_appliances = Appliances()
|
||||||
_appliances.density = archetype.appliances.density / cte.METERS_TO_FEET ** 2
|
_appliances.density = archetype.appliances.density
|
||||||
_appliances.convective_fraction = archetype.appliances.convective_fraction
|
_appliances.convective_fraction = archetype.appliances.convective_fraction
|
||||||
_appliances.radiative_fraction = archetype.appliances.radiative_fraction
|
_appliances.radiative_fraction = archetype.appliances.radiative_fraction
|
||||||
_appliances.latent_fraction = archetype.appliances.latent_fraction
|
_appliances.latent_fraction = archetype.appliances.latent_fraction
|
||||||
|
|
|
@ -106,7 +106,7 @@ class UsageHelper:
|
||||||
'C-14 Gymnasium': 'C-14 Gymnasium'}
|
'C-14 Gymnasium': 'C-14 Gymnasium'}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def comnet_from_libs_usage(usage):
|
def comnet_from_hub_usage(usage):
|
||||||
"""
|
"""
|
||||||
Get Comnet usage from the given internal usage key
|
Get Comnet usage from the given internal usage key
|
||||||
:param usage: str
|
:param usage: str
|
||||||
|
@ -115,7 +115,7 @@ class UsageHelper:
|
||||||
try:
|
try:
|
||||||
return UsageHelper._usage_to_comnet[usage]
|
return UsageHelper._usage_to_comnet[usage]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
sys.stderr.write('Error: keyword not found to translate from libs_usage to comnet usage.\n')
|
sys.stderr.write('Error: keyword not found to translate from hub_usage to comnet usage.\n')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def schedules_key(usage):
|
def schedules_key(usage):
|
||||||
|
@ -129,3 +129,41 @@ class UsageHelper:
|
||||||
except KeyError:
|
except KeyError:
|
||||||
sys.stderr.write('Error: Comnet keyword not found. An update of the Comnet files might have been '
|
sys.stderr.write('Error: Comnet keyword not found. An update of the Comnet files might have been '
|
||||||
'done changing the keywords.\n')
|
'done changing the keywords.\n')
|
||||||
|
|
||||||
|
_usage_to_nrcan = {
|
||||||
|
cte.RESIDENTIAL: 'Multi-unit residential',
|
||||||
|
cte.SINGLE_FAMILY_HOUSE: 'Multi-unit residential',
|
||||||
|
cte.MULTI_FAMILY_HOUSE: 'Multi-unit residential',
|
||||||
|
cte.EDUCATION: 'School/university',
|
||||||
|
cte.SCHOOL_WITHOUT_SHOWER: 'School/university',
|
||||||
|
cte.SCHOOL_WITH_SHOWER: 'School/university',
|
||||||
|
cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'Retail',
|
||||||
|
cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'Retail',
|
||||||
|
cte.HOTEL: 'Hotel',
|
||||||
|
cte.HOTEL_MEDIUM_CLASS: 'Hotel',
|
||||||
|
cte.DORMITORY: 'Dormitory',
|
||||||
|
cte.INDUSTRY: 'Manufacturing Facility',
|
||||||
|
cte.RESTAURANT: 'Dining - family',
|
||||||
|
cte.HEALTH_CARE: 'Hospital',
|
||||||
|
cte.RETIREMENT_HOME_OR_ORPHANAGE: 'Multi-unit residential',
|
||||||
|
cte.OFFICE_AND_ADMINISTRATION: 'Office',
|
||||||
|
cte.EVENT_LOCATION: 'Convention centre',
|
||||||
|
cte.HALL: 'Convention centre',
|
||||||
|
cte.SPORTS_LOCATION: 'Gymnasium',
|
||||||
|
cte.LABOR: 'Gymnasium',
|
||||||
|
cte.GREEN_HOUSE: cte.GREEN_HOUSE,
|
||||||
|
cte.NON_HEATED: cte.NON_HEATED
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def nrcan_from_hub_usage(usage):
|
||||||
|
"""
|
||||||
|
Get Nrcan usage from the given internal usage key
|
||||||
|
:param usage: str
|
||||||
|
:return: str
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return UsageHelper._usage_to_nrcan[usage]
|
||||||
|
except KeyError:
|
||||||
|
sys.stderr.write('Error: keyword not found to translate from hub_usage to nrcan usage.\n')
|
||||||
|
|
||||||
|
|
|
@ -1,280 +0,0 @@
|
||||||
"""
|
|
||||||
Hft-based interface, it reads format defined within the CERC team (based on that one used in SimStadt and developed by
|
|
||||||
the IAF team at hft-Stuttgart)
|
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
||||||
Copyright © 2022 Concordia CERC group
|
|
||||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
|
||||||
"""
|
|
||||||
import xmltodict
|
|
||||||
import copy
|
|
||||||
from city_model_structure.building_demand.usage import Usage
|
|
||||||
from city_model_structure.building_demand.internal_gain import InternalGain
|
|
||||||
from city_model_structure.building_demand.occupancy import Occupancy
|
|
||||||
from city_model_structure.building_demand.appliances import Appliances
|
|
||||||
from city_model_structure.building_demand.thermal_control import ThermalControl
|
|
||||||
from city_model_structure.attributes.schedule import Schedule
|
|
||||||
import helpers.constants as cte
|
|
||||||
from imports.usage.helpers.usage_helper import UsageHelper
|
|
||||||
|
|
||||||
|
|
||||||
class HftUsageInterface:
|
|
||||||
"""
|
|
||||||
HftUsageInterface abstract class
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, base_path, usage_file='ca_library_reduced.xml'):
|
|
||||||
path = str(base_path / usage_file)
|
|
||||||
self._usage_archetypes = []
|
|
||||||
with open(path) as xml:
|
|
||||||
self._archetypes = xmltodict.parse(xml.read(), force_list=('zoneUsageVariant', 'zoneUsageType'))
|
|
||||||
for zone_usage_type in self._archetypes['buildingUsageLibrary']['zoneUsageType']:
|
|
||||||
usage = zone_usage_type['id']
|
|
||||||
usage_archetype = self._parse_zone_usage_type(usage, zone_usage_type)
|
|
||||||
self._usage_archetypes.append(usage_archetype)
|
|
||||||
if 'zoneUsageVariant' in zone_usage_type:
|
|
||||||
for usage_zone_variant in zone_usage_type['zoneUsageVariant']:
|
|
||||||
usage = usage_zone_variant['id']
|
|
||||||
usage_archetype_variant = self._parse_zone_usage_variant(usage, usage_archetype, usage_zone_variant)
|
|
||||||
self._usage_archetypes.append(usage_archetype_variant)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _parse_zone_usage_type(usage, zone_usage_type):
|
|
||||||
usage_zone_archetype = Usage()
|
|
||||||
usage_zone_archetype.name = usage
|
|
||||||
|
|
||||||
if 'occupancy' in zone_usage_type:
|
|
||||||
_occupancy = Occupancy()
|
|
||||||
_occupancy.occupancy_density = zone_usage_type['occupancy']['occupancyDensity'] #todo: check units
|
|
||||||
|
|
||||||
if 'internGains' in zone_usage_type['occupancy']:
|
|
||||||
_internal_gain = InternalGain()
|
|
||||||
_internal_gain.latent_fraction = zone_usage_type['occupancy']['internGains']['latentFraction']
|
|
||||||
_internal_gain.convective_fraction = zone_usage_type['occupancy']['internGains']['convectiveFraction']
|
|
||||||
_internal_gain.average_internal_gain = zone_usage_type['occupancy']['internGains']['averageInternGainPerSqm']
|
|
||||||
_internal_gain.radiative_fraction = zone_usage_type['occupancy']['internGains']['radiantFraction']
|
|
||||||
if 'load' in zone_usage_type['occupancy']['internGains']:
|
|
||||||
_schedule = Schedule()
|
|
||||||
_schedule.type = 'internal gains load'
|
|
||||||
_schedule.time_range = cte.DAY
|
|
||||||
_schedule.time_step = cte.HOUR
|
|
||||||
_schedule.data_type = cte.ANY_NUMBER
|
|
||||||
_schedule.day_types = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY, cte.SATURDAY,
|
|
||||||
cte.SUNDAY]
|
|
||||||
_values = zone_usage_type['occupancy']['internGains']['load']['weekDayProfile']['values']
|
|
||||||
while ' ' in _values:
|
|
||||||
_values = _values.replace(' ', ' ')
|
|
||||||
_values = _values.split()
|
|
||||||
_values_float = []
|
|
||||||
for _value in _values:
|
|
||||||
_values_float.append(float(_value))
|
|
||||||
_schedule.values = _values_float
|
|
||||||
_internal_gain.schedules = [_schedule]
|
|
||||||
|
|
||||||
usage_zone_archetype.internal_gains = [_internal_gain]
|
|
||||||
|
|
||||||
usage_zone_archetype.hours_day = zone_usage_type['occupancy']['usageHoursPerDay']
|
|
||||||
usage_zone_archetype.days_year = zone_usage_type['occupancy']['usageDaysPerYear']
|
|
||||||
usage_zone_archetype.occupancy = _occupancy
|
|
||||||
|
|
||||||
if 'endUses' in zone_usage_type:
|
|
||||||
_thermal_control = ThermalControl()
|
|
||||||
if 'space_heating' in zone_usage_type['endUses']:
|
|
||||||
_thermal_control.mean_heating_set_point = \
|
|
||||||
zone_usage_type['endUses']['space_heating']['heatingSetPointTemperature']
|
|
||||||
_thermal_control.heating_set_back = zone_usage_type['endUses']['space_heating']['heatingSetBackTemperature']
|
|
||||||
if 'schedule' in zone_usage_type['endUses']['space_heating']:
|
|
||||||
_schedule = Schedule()
|
|
||||||
_schedule.type = 'heating temperature'
|
|
||||||
_schedule.time_range = cte.DAY
|
|
||||||
_schedule.time_step = cte.HOUR
|
|
||||||
_schedule.data_type = cte.ANY_NUMBER
|
|
||||||
_schedule.day_types = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY, cte.SATURDAY,
|
|
||||||
cte.SUNDAY]
|
|
||||||
_values = zone_usage_type['endUses']['space_heating']['schedule']['weekDayProfile']['values']
|
|
||||||
while ' ' in _values:
|
|
||||||
_values = _values.replace(' ', ' ')
|
|
||||||
_values = _values.split()
|
|
||||||
_values_float = []
|
|
||||||
for _value in _values:
|
|
||||||
_values_float.append(float(_value))
|
|
||||||
_schedule.values = _values_float
|
|
||||||
_thermal_control.heating_set_point_schedules = [_schedule]
|
|
||||||
|
|
||||||
if 'space_cooling' in zone_usage_type['endUses']:
|
|
||||||
_thermal_control.mean_cooling_set_point = \
|
|
||||||
zone_usage_type['endUses']['space_cooling']['coolingSetPointTemperature']
|
|
||||||
if 'schedule' in zone_usage_type['endUses']['space_cooling']:
|
|
||||||
_schedule = Schedule()
|
|
||||||
_schedule.type = 'cooling temperature'
|
|
||||||
_schedule.time_range = cte.DAY
|
|
||||||
_schedule.time_step = cte.HOUR
|
|
||||||
_schedule.data_type = cte.ANY_NUMBER
|
|
||||||
_schedule.day_types = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY, cte.SATURDAY,
|
|
||||||
cte.SUNDAY]
|
|
||||||
_values = zone_usage_type['endUses']['space_cooling']['schedule']['weekDayProfile']['values']
|
|
||||||
while ' ' in _values:
|
|
||||||
_values = _values.replace(' ', ' ')
|
|
||||||
_values = _values.split()
|
|
||||||
_values_float = []
|
|
||||||
for _value in _values:
|
|
||||||
_values_float.append(float(_value))
|
|
||||||
_schedule.values = _values_float
|
|
||||||
_thermal_control.cooling_set_point_schedules = [_schedule]
|
|
||||||
|
|
||||||
usage_zone_archetype.thermal_control = _thermal_control
|
|
||||||
|
|
||||||
if 'ventilation' in zone_usage_type['endUses'] and zone_usage_type['endUses']['ventilation'] is not None:
|
|
||||||
usage_zone_archetype.mechanical_air_change = \
|
|
||||||
zone_usage_type['endUses']['ventilation']['mechanicalAirChangeRate']
|
|
||||||
|
|
||||||
# todo: not used or assigned anywhere
|
|
||||||
if 'domestic_hot_water' in zone_usage_type['endUses']:
|
|
||||||
# liters to cubic meters
|
|
||||||
dhw_average_volume_pers_day = float(
|
|
||||||
zone_usage_type['endUses']['domestic_hot_water']['averageVolumePerPersAndDay']) / 1000
|
|
||||||
dhw_preparation_temperature = zone_usage_type['endUses']['domestic_hot_water']['preparationTemperature']
|
|
||||||
|
|
||||||
if 'all_electrical_appliances' in zone_usage_type['endUses']:
|
|
||||||
if 'averageConsumptionPerSqmAndYear' in zone_usage_type['endUses']['all_electrical_appliances']:
|
|
||||||
# kWh to J
|
|
||||||
usage_zone_archetype.electrical_app_average_consumption_sqm_year = \
|
|
||||||
float(zone_usage_type['endUses']['all_electrical_appliances']['averageConsumptionPerSqmAndYear']) \
|
|
||||||
* cte.KILO_WATTS_HOUR_TO_JULES
|
|
||||||
|
|
||||||
if 'appliance' in zone_usage_type:
|
|
||||||
_appliances = Appliances()
|
|
||||||
_appliances.density = zone_usage_type['appliance']['#text'] #todo: check units
|
|
||||||
|
|
||||||
usage_zone_archetype.appliances = _appliances
|
|
||||||
|
|
||||||
return usage_zone_archetype
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _parse_zone_usage_variant(usage, usage_zone, usage_zone_variant):
|
|
||||||
# the variants mimic the inheritance concept from OOP
|
|
||||||
usage_zone_archetype = copy.deepcopy(usage_zone)
|
|
||||||
usage_zone_archetype.name = usage
|
|
||||||
|
|
||||||
if 'occupancy' in usage_zone_variant:
|
|
||||||
_occupancy = Occupancy()
|
|
||||||
if 'occupancyDensity' in usage_zone_variant['occupancy']:
|
|
||||||
_occupancy.occupancy_density = usage_zone_variant['occupancy']['occupancyDensity'] # todo: check units
|
|
||||||
if 'usageHoursPerDay' in usage_zone_variant['occupancy']:
|
|
||||||
usage_zone_archetype.hours_day = usage_zone_variant['occupancy']['usageHoursPerDay']
|
|
||||||
if 'usageDaysPerYear' in usage_zone_variant['occupancy']:
|
|
||||||
usage_zone_archetype.days_year = usage_zone_variant['occupancy']['usageDaysPerYear']
|
|
||||||
usage_zone_archetype.occupancy = _occupancy
|
|
||||||
|
|
||||||
if 'internGains' in usage_zone_variant['occupancy']:
|
|
||||||
_internal_gain = InternalGain()
|
|
||||||
if 'latentFraction' in usage_zone_variant['occupancy']['internGains']:
|
|
||||||
_internal_gain.latent_fraction = usage_zone_variant['occupancy']['internGains']['latentFraction']
|
|
||||||
if 'convectiveFraction' in usage_zone_variant['occupancy']['internGains']:
|
|
||||||
_internal_gain.convective_fraction = usage_zone_variant['occupancy']['internGains']['convectiveFraction']
|
|
||||||
if 'averageInternGainPerSqm' in usage_zone_variant['occupancy']['internGains']:
|
|
||||||
_internal_gain.average_internal_gain = \
|
|
||||||
usage_zone_variant['occupancy']['internGains']['averageInternGainPerSqm']
|
|
||||||
if 'radiantFraction' in usage_zone_variant['occupancy']['internGains']:
|
|
||||||
_internal_gain.radiative_fraction = usage_zone_variant['occupancy']['internGains']['radiantFraction']
|
|
||||||
if 'load' in usage_zone_variant['occupancy']['internGains']:
|
|
||||||
_schedule = Schedule()
|
|
||||||
_schedule.type = 'internal gains load'
|
|
||||||
_schedule.time_range = cte.DAY
|
|
||||||
_schedule.time_step = cte.HOUR
|
|
||||||
_schedule.data_type = cte.ANY_NUMBER
|
|
||||||
_schedule.day_types = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY, cte.SATURDAY,
|
|
||||||
cte.SUNDAY]
|
|
||||||
_values = usage_zone_variant['occupancy']['internGains']['load']['weekDayProfile']['values']
|
|
||||||
while ' ' in _values:
|
|
||||||
_values = _values.replace(' ', ' ')
|
|
||||||
_values = _values.split()
|
|
||||||
_values_float = []
|
|
||||||
for _value in _values:
|
|
||||||
_values_float.append(float(_value))
|
|
||||||
_schedule.values = _values_float
|
|
||||||
_internal_gain.schedules = [_schedule]
|
|
||||||
|
|
||||||
usage_zone_archetype.internal_gains = [_internal_gain]
|
|
||||||
|
|
||||||
if 'endUses' in usage_zone_variant:
|
|
||||||
_thermal_control = ThermalControl()
|
|
||||||
if 'space_heating' in usage_zone_variant['endUses']:
|
|
||||||
if 'heatingSetPointTemperature' in usage_zone_variant['endUses']['space_heating']:
|
|
||||||
_thermal_control.mean_heating_set_point = \
|
|
||||||
usage_zone_variant['endUses']['space_heating']['heatingSetPointTemperature']
|
|
||||||
if 'heatingSetBackTemperature' in usage_zone_variant['endUses']['space_heating']:
|
|
||||||
_thermal_control.heating_set_back = usage_zone_variant['endUses']['space_heating']['heatingSetBackTemperature']
|
|
||||||
if 'schedule' in usage_zone_variant['endUses']['space_heating']:
|
|
||||||
_schedule = Schedule()
|
|
||||||
_schedule.type = 'heating temperature'
|
|
||||||
_schedule.time_range = cte.DAY
|
|
||||||
_schedule.time_step = cte.HOUR
|
|
||||||
_schedule.data_type = cte.ANY_NUMBER
|
|
||||||
_schedule.day_types = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY, cte.SATURDAY,
|
|
||||||
cte.SUNDAY]
|
|
||||||
_values = usage_zone_variant['endUses']['space_heating']['schedule']['weekDayProfile']['values']
|
|
||||||
while ' ' in _values:
|
|
||||||
_values = _values.replace(' ', ' ')
|
|
||||||
_values = _values.split()
|
|
||||||
_values_float = []
|
|
||||||
for _value in _values:
|
|
||||||
_values_float.append(float(_value))
|
|
||||||
_schedule.values = _values_float
|
|
||||||
_thermal_control.heating_set_point_schedules = [_schedule]
|
|
||||||
|
|
||||||
if 'space_cooling' in usage_zone_variant['endUses'] and \
|
|
||||||
usage_zone_variant['endUses']['space_cooling'] is not None:
|
|
||||||
if 'coolingSetPointTemperature' in usage_zone_variant['endUses']['space_cooling']:
|
|
||||||
_thermal_control.mean_cooling_set_point = \
|
|
||||||
usage_zone_variant['endUses']['space_cooling']['coolingSetPointTemperature']
|
|
||||||
if 'schedule' in usage_zone_variant['endUses']['space_cooling']:
|
|
||||||
_schedule = Schedule()
|
|
||||||
_schedule.type = 'cooling temperature'
|
|
||||||
_schedule.time_range = cte.DAY
|
|
||||||
_schedule.time_step = cte.HOUR
|
|
||||||
_schedule.data_type = cte.ANY_NUMBER
|
|
||||||
_schedule.day_types = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY, cte.SATURDAY,
|
|
||||||
cte.SUNDAY]
|
|
||||||
_values = usage_zone_variant['endUses']['space_cooling']['schedule']['weekDayProfile']['values']
|
|
||||||
while ' ' in _values:
|
|
||||||
_values = _values.replace(' ', ' ')
|
|
||||||
_values = _values.split()
|
|
||||||
_values_float = []
|
|
||||||
for _value in _values:
|
|
||||||
_values_float.append(float(_value))
|
|
||||||
_schedule.values = _values_float
|
|
||||||
_thermal_control.cooling_set_point_schedules = [_schedule]
|
|
||||||
|
|
||||||
usage_zone_archetype.thermal_control = _thermal_control
|
|
||||||
|
|
||||||
if 'ventilation' in usage_zone_variant['endUses'] and usage_zone_variant['endUses']['ventilation'] is not None:
|
|
||||||
usage_zone_archetype.mechanical_air_change = \
|
|
||||||
usage_zone_variant['endUses']['ventilation']['mechanicalAirChangeRate']
|
|
||||||
|
|
||||||
if 'appliance' in usage_zone_variant:
|
|
||||||
_appliances = Appliances()
|
|
||||||
_appliances.density = usage_zone_variant['appliance']['#text'] # todo: check units
|
|
||||||
|
|
||||||
usage_zone_archetype.appliances = _appliances
|
|
||||||
|
|
||||||
return usage_zone_archetype
|
|
||||||
|
|
||||||
def _search_archetype(self, libs_usage):
|
|
||||||
building_usage = UsageHelper().hft_from_libs_usage(libs_usage)
|
|
||||||
for building_archetype in self._usage_archetypes:
|
|
||||||
if building_archetype.name == building_usage:
|
|
||||||
return building_archetype
|
|
||||||
return None
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _assign_values(usage, archetype):
|
|
||||||
usage_zone = Usage()
|
|
||||||
usage_zone.name = usage
|
|
||||||
usage_zone.internal_gains = copy.deepcopy(archetype.internal_gains)
|
|
||||||
usage_zone.mechanical_air_change = archetype.mechanical_air_change
|
|
||||||
usage_zone.occupancy = copy.deepcopy(archetype.occupancy)
|
|
||||||
usage_zone.appliances = copy.deepcopy(archetype.appliances)
|
|
||||||
usage_zone.thermal_control = copy.deepcopy(archetype.thermal_control)
|
|
||||||
usage_zone.days_year = archetype.days_year
|
|
||||||
usage_zone.hours_day = archetype.hours_day
|
|
||||||
return usage_zone
|
|
|
@ -1,42 +0,0 @@
|
||||||
"""
|
|
||||||
HftUsageParameters model the usage properties
|
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
||||||
Copyright © 2022 Concordia CERC group
|
|
||||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
|
||||||
"""
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from imports.geometry.helpers.geometry_helper import GeometryHelper
|
|
||||||
from imports.usage.hft_usage_interface import HftUsageInterface
|
|
||||||
from imports.usage.helpers.usage_helper import UsageHelper
|
|
||||||
|
|
||||||
|
|
||||||
class HftUsageParameters(HftUsageInterface):
|
|
||||||
"""
|
|
||||||
HftUsageParameters class
|
|
||||||
"""
|
|
||||||
def __init__(self, city, base_path):
|
|
||||||
super().__init__(base_path, 'de_library.xml')
|
|
||||||
self._city = city
|
|
||||||
|
|
||||||
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().libs_usage_from_libs_function(building.function)
|
|
||||||
try:
|
|
||||||
archetype = self._search_archetype(usage)
|
|
||||||
except KeyError:
|
|
||||||
sys.stderr.write(f'Building {building.name} has unknown archetype for building function:'
|
|
||||||
f' {building.function}, that assigns building usage as '
|
|
||||||
f'{GeometryHelper().libs_usage_from_libs_function(building.function)}\n')
|
|
||||||
return
|
|
||||||
|
|
||||||
for internal_zone in building.internal_zones:
|
|
||||||
libs_usage = GeometryHelper().libs_usage_from_libs_function(building.function)
|
|
||||||
usage_zone = self._assign_values(UsageHelper().hft_from_libs_usage(libs_usage), archetype)
|
|
||||||
usage_zone.percentage = 1
|
|
||||||
internal_zone.usages = [usage_zone]
|
|
191
imports/usage/nrcan_usage_parameters.py
Normal file
191
imports/usage/nrcan_usage_parameters.py
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
"""
|
||||||
|
NrcanUsageParameters extracts the usage properties from NRCAN catalog and assigns to each building
|
||||||
|
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 copy
|
||||||
|
import sys
|
||||||
|
import numpy
|
||||||
|
|
||||||
|
import helpers.constants as cte
|
||||||
|
from imports.usage.helpers.usage_helper import UsageHelper
|
||||||
|
from city_model_structure.building_demand.usage import Usage
|
||||||
|
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
|
||||||
|
from city_model_structure.building_demand.thermal_control import ThermalControl
|
||||||
|
from city_model_structure.attributes.schedule import Schedule
|
||||||
|
from city_model_structure.building_demand.internal_gain import InternalGain
|
||||||
|
from catalog_factories.usage_catalog_factory import UsageCatalogFactory
|
||||||
|
|
||||||
|
|
||||||
|
class NrcanUsageParameters:
|
||||||
|
"""
|
||||||
|
NrcanUsageParameters class
|
||||||
|
"""
|
||||||
|
def __init__(self, city, base_path):
|
||||||
|
self._city = city
|
||||||
|
self._path = base_path
|
||||||
|
|
||||||
|
def enrich_buildings(self):
|
||||||
|
"""
|
||||||
|
Returns the city with the usage parameters assigned to the buildings
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
city = self._city
|
||||||
|
nrcan_catalog = UsageCatalogFactory('nrcan').catalog
|
||||||
|
|
||||||
|
for building in city.buildings:
|
||||||
|
usage_name = UsageHelper.nrcan_from_hub_usage(building.function)
|
||||||
|
try:
|
||||||
|
archetype_usage = self._search_archetypes(nrcan_catalog, usage_name)
|
||||||
|
except KeyError:
|
||||||
|
sys.stderr.write(f'Building {building.name} has unknown usage archetype for building function:'
|
||||||
|
f' {building.function}')
|
||||||
|
return
|
||||||
|
|
||||||
|
for internal_zone in building.internal_zones:
|
||||||
|
if internal_zone.area is None:
|
||||||
|
raise Exception('Internal zone area not defined, ACH cannot be calculated')
|
||||||
|
if internal_zone.volume is None:
|
||||||
|
raise Exception('Internal zone volume not defined, ACH cannot be calculated')
|
||||||
|
if internal_zone.area <= 0:
|
||||||
|
raise Exception('Internal zone area is zero, ACH cannot be calculated')
|
||||||
|
volume_per_area = internal_zone.volume / internal_zone.area
|
||||||
|
usage_zone = Usage()
|
||||||
|
usage_zone.name = usage_name
|
||||||
|
self._assign_values(usage_zone, archetype_usage, volume_per_area)
|
||||||
|
usage_zone.percentage = 1
|
||||||
|
self._calculate_reduced_values_from_extended_library(usage_zone, archetype_usage)
|
||||||
|
|
||||||
|
internal_zone.usages = [usage_zone]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _search_archetypes(comnet_catalog, usage_name):
|
||||||
|
comnet_archetypes = comnet_catalog.entries('archetypes').usages
|
||||||
|
for building_archetype in comnet_archetypes:
|
||||||
|
if str(usage_name) == str(building_archetype.name):
|
||||||
|
return building_archetype
|
||||||
|
raise KeyError('archetype not found')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _assign_values(usage_zone, archetype, volume_per_area):
|
||||||
|
# Due to the fact that python is not a typed language, the wrong object type is assigned to
|
||||||
|
# usage_zone.occupancy when writing usage_zone.occupancy = archetype.occupancy.
|
||||||
|
# Same happens for lighting and appliances. Therefore, this walk around has been done.
|
||||||
|
if archetype.mechanical_air_change > 0:
|
||||||
|
usage_zone.mechanical_air_change = archetype.mechanical_air_change
|
||||||
|
elif archetype.ventilation_rate > 0:
|
||||||
|
usage_zone.mechanical_air_change = archetype.ventilation_rate / volume_per_area \
|
||||||
|
* cte.HOUR_TO_MINUTES * cte.MINUTES_TO_SECONDS
|
||||||
|
else:
|
||||||
|
usage_zone.mechanical_air_change = 0
|
||||||
|
_occupancy = Occupancy()
|
||||||
|
_occupancy.occupancy_density = archetype.occupancy.occupancy_density
|
||||||
|
_occupancy.sensible_radiative_internal_gain = archetype.occupancy.sensible_radiative_internal_gain
|
||||||
|
_occupancy.latent_internal_gain = archetype.occupancy.latent_internal_gain
|
||||||
|
_occupancy.sensible_convective_internal_gain = archetype.occupancy.sensible_convective_internal_gain
|
||||||
|
_occupancy.occupancy_schedules = archetype.occupancy.occupancy_schedules
|
||||||
|
usage_zone.occupancy = _occupancy
|
||||||
|
_lighting = Lighting()
|
||||||
|
_lighting.density = archetype.lighting.density
|
||||||
|
_lighting.convective_fraction = archetype.lighting.convective_fraction
|
||||||
|
_lighting.radiative_fraction = archetype.lighting.radiative_fraction
|
||||||
|
_lighting.latent_fraction = archetype.lighting.latent_fraction
|
||||||
|
_lighting.schedules = archetype.lighting.schedules
|
||||||
|
usage_zone.lighting = _lighting
|
||||||
|
_appliances = Appliances()
|
||||||
|
_appliances.density = archetype.appliances.density
|
||||||
|
_appliances.convective_fraction = archetype.appliances.convective_fraction
|
||||||
|
_appliances.radiative_fraction = archetype.appliances.radiative_fraction
|
||||||
|
_appliances.latent_fraction = archetype.appliances.latent_fraction
|
||||||
|
_appliances.schedules = archetype.appliances.schedules
|
||||||
|
usage_zone.appliances = _appliances
|
||||||
|
_control = ThermalControl()
|
||||||
|
_control.cooling_set_point_schedules = archetype.thermal_control.cooling_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
|
||||||
|
usage_zone.thermal_control = _control
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _calculate_reduced_values_from_extended_library(usage_zone, archetype):
|
||||||
|
number_of_days_per_type = {'WD': 251, 'Sat': 52, 'Sun': 62}
|
||||||
|
total = 0
|
||||||
|
for schedule in archetype.thermal_control.hvac_availability_schedules:
|
||||||
|
if schedule.day_types[0] == cte.SATURDAY:
|
||||||
|
for value in schedule.values:
|
||||||
|
total += value * number_of_days_per_type['Sat']
|
||||||
|
elif schedule.day_types[0] == cte.SUNDAY:
|
||||||
|
for value in schedule.values:
|
||||||
|
total += value * number_of_days_per_type['Sun']
|
||||||
|
else:
|
||||||
|
for value in schedule.values:
|
||||||
|
total += value * number_of_days_per_type['WD']
|
||||||
|
|
||||||
|
usage_zone.hours_day = total / 365
|
||||||
|
usage_zone.days_year = 365
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _calculate_internal_gains(archetype):
|
||||||
|
|
||||||
|
_DAYS = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY, cte.SATURDAY, cte.SUNDAY, cte.HOLIDAY]
|
||||||
|
_number_of_days_per_type = [51, 50, 50, 50, 50, 52, 52, 10]
|
||||||
|
|
||||||
|
_mean_internal_gain = InternalGain()
|
||||||
|
_mean_internal_gain.type = 'mean_value_of_internal_gains'
|
||||||
|
_base_schedule = Schedule()
|
||||||
|
_base_schedule.type = cte.INTERNAL_GAINS
|
||||||
|
_base_schedule.time_range = cte.DAY
|
||||||
|
_base_schedule.time_step = cte.HOUR
|
||||||
|
_base_schedule.data_type = cte.FRACTION
|
||||||
|
|
||||||
|
_latent_heat_gain = archetype.occupancy.latent_internal_gain
|
||||||
|
_convective_heat_gain = archetype.occupancy.sensible_convective_internal_gain
|
||||||
|
_radiative_heat_gain = archetype.occupancy.sensible_radiative_internal_gain
|
||||||
|
_total_heat_gain = (_latent_heat_gain + _convective_heat_gain + _radiative_heat_gain)
|
||||||
|
|
||||||
|
_schedule_values = numpy.zeros([24, 8])
|
||||||
|
_sum = 0
|
||||||
|
for day, _schedule in enumerate(archetype.occupancy.schedules):
|
||||||
|
for v, value in enumerate(_schedule.values):
|
||||||
|
_schedule_values[v, day] = value * _total_heat_gain
|
||||||
|
_sum += value * _total_heat_gain * _number_of_days_per_type[day]
|
||||||
|
|
||||||
|
_total_heat_gain += archetype.lighting.density + archetype.appliances.density
|
||||||
|
_latent_heat_gain += archetype.lighting.latent_fraction * archetype.lighting.density\
|
||||||
|
+ archetype.appliances.latent_fraction * archetype.appliances.density
|
||||||
|
_radiative_heat_gain = archetype.lighting.radiative_fraction * archetype.lighting.density \
|
||||||
|
+ archetype.appliances.radiative_fraction * archetype.appliances.density
|
||||||
|
_convective_heat_gain = archetype.lighting.convective_fraction * archetype.lighting.density \
|
||||||
|
+ archetype.appliances.convective_fraction * archetype.appliances.density
|
||||||
|
|
||||||
|
for day, _schedule in enumerate(archetype.lighting.schedules):
|
||||||
|
for v, value in enumerate(_schedule.values):
|
||||||
|
_schedule_values[v, day] += value * archetype.lighting.density
|
||||||
|
_sum += value * archetype.lighting.density * _number_of_days_per_type[day]
|
||||||
|
|
||||||
|
for day, _schedule in enumerate(archetype.appliances.schedules):
|
||||||
|
for v, value in enumerate(_schedule.values):
|
||||||
|
_schedule_values[v, day] += value * archetype.appliances.density
|
||||||
|
_sum += value * archetype.appliances.density * _number_of_days_per_type[day]
|
||||||
|
|
||||||
|
_latent_fraction = _latent_heat_gain / _total_heat_gain
|
||||||
|
_radiative_fraction = _radiative_heat_gain / _total_heat_gain
|
||||||
|
_convective_fraction = _convective_heat_gain / _total_heat_gain
|
||||||
|
_average_internal_gain = _sum / _total_heat_gain
|
||||||
|
|
||||||
|
_schedules = []
|
||||||
|
for day in range(0, len(_DAYS)):
|
||||||
|
_schedule = copy.deepcopy(_base_schedule)
|
||||||
|
_schedule.day_types = [_DAYS[day]]
|
||||||
|
_schedule.values = _schedule_values[:day]
|
||||||
|
_schedules.append(_schedule)
|
||||||
|
|
||||||
|
_mean_internal_gain.average_internal_gain = _average_internal_gain
|
||||||
|
_mean_internal_gain.latent_fraction = _latent_fraction
|
||||||
|
_mean_internal_gain.convective_fraction = _convective_fraction
|
||||||
|
_mean_internal_gain.radiative_fraction = _radiative_fraction
|
||||||
|
_mean_internal_gain.schedules = _schedules
|
||||||
|
|
||||||
|
return [_mean_internal_gain]
|
|
@ -7,9 +7,8 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
"""
|
"""
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from imports.usage.hft_usage_parameters import HftUsageParameters
|
|
||||||
from imports.usage.comnet_usage_parameters import ComnetUsageParameters
|
from imports.usage.comnet_usage_parameters import ComnetUsageParameters
|
||||||
|
from imports.usage.nrcan_usage_parameters import NrcanUsageParameters
|
||||||
|
|
||||||
class UsageFactory:
|
class UsageFactory:
|
||||||
"""
|
"""
|
||||||
|
@ -22,20 +21,19 @@ class UsageFactory:
|
||||||
self._city = city
|
self._city = city
|
||||||
self._base_path = base_path
|
self._base_path = base_path
|
||||||
|
|
||||||
def _hft(self):
|
|
||||||
"""
|
|
||||||
Enrich the city with HFT usage library
|
|
||||||
"""
|
|
||||||
self._city.level_of_detail.usage = 2
|
|
||||||
HftUsageParameters(self._city, self._base_path).enrich_buildings()
|
|
||||||
|
|
||||||
def _comnet(self):
|
def _comnet(self):
|
||||||
"""
|
"""
|
||||||
Enrich the city with COMNET usage library
|
Enrich the city with COMNET usage library
|
||||||
"""
|
"""
|
||||||
self._city.level_of_detail.usage = 2
|
self._city.level_of_detail.usage_name = 2
|
||||||
ComnetUsageParameters(self._city, self._base_path).enrich_buildings()
|
ComnetUsageParameters(self._city, self._base_path).enrich_buildings()
|
||||||
|
|
||||||
|
def _nrcan(self):
|
||||||
|
"""
|
||||||
|
Enrich the city with NRCAN usage library
|
||||||
|
"""
|
||||||
|
return NrcanUsageParameters(self._city, self._base_path).enrich_buildings()
|
||||||
|
|
||||||
def enrich(self):
|
def enrich(self):
|
||||||
"""
|
"""
|
||||||
Enrich the city given to the class using the usage factory given handler
|
Enrich the city given to the class using the usage factory given handler
|
||||||
|
|
|
@ -122,7 +122,7 @@ class TestConstructionFactory(TestCase):
|
||||||
self.assertIsNone(thermal_zone.ordinate_number, 'thermal_zone ordinate number is not none')
|
self.assertIsNone(thermal_zone.ordinate_number, 'thermal_zone ordinate number is not none')
|
||||||
self.assertIsNotNone(thermal_zone.view_factors_matrix, 'thermal_zone view factors matrix is none')
|
self.assertIsNotNone(thermal_zone.view_factors_matrix, 'thermal_zone view factors matrix is none')
|
||||||
self.assertIsNotNone(thermal_zone.total_floor_area, 'thermal zone total_floor_area is none')
|
self.assertIsNotNone(thermal_zone.total_floor_area, 'thermal zone total_floor_area is none')
|
||||||
self.assertIsNone(thermal_zone.usage, 'thermal_zone usage is not none')
|
self.assertIsNone(thermal_zone.usage_name, 'thermal_zone usage is not none')
|
||||||
self.assertIsNone(thermal_zone.hours_day, 'thermal_zone hours a day is not none')
|
self.assertIsNone(thermal_zone.hours_day, 'thermal_zone hours a day is not none')
|
||||||
self.assertIsNone(thermal_zone.days_year, 'thermal_zone days a year is not none')
|
self.assertIsNone(thermal_zone.days_year, 'thermal_zone days a year is not none')
|
||||||
self.assertIsNone(thermal_zone.mechanical_air_change, 'thermal_zone mechanical air change is not none')
|
self.assertIsNone(thermal_zone.mechanical_air_change, 'thermal_zone mechanical air change is not none')
|
||||||
|
|
|
@ -55,7 +55,7 @@ class TestGeometryFactory(TestCase):
|
||||||
|
|
||||||
def _check_thermal_zone(self, thermal_zone):
|
def _check_thermal_zone(self, thermal_zone):
|
||||||
self.assertIsNotNone(thermal_zone.id, 'thermal_zone id is none')
|
self.assertIsNotNone(thermal_zone.id, 'thermal_zone id is none')
|
||||||
self.assertIsNotNone(thermal_zone.usage, 'thermal_zone usage is not none')
|
self.assertIsNotNone(thermal_zone.usage_name, 'thermal_zone usage is not none')
|
||||||
self.assertIsNotNone(thermal_zone.hours_day, 'thermal_zone hours a day is none')
|
self.assertIsNotNone(thermal_zone.hours_day, 'thermal_zone hours a day is none')
|
||||||
self.assertIsNotNone(thermal_zone.days_year, 'thermal_zone days a year is none')
|
self.assertIsNotNone(thermal_zone.days_year, 'thermal_zone days a year is none')
|
||||||
self.assertIsNotNone(thermal_zone.occupancy, 'thermal_zone occupancy is none')
|
self.assertIsNotNone(thermal_zone.occupancy, 'thermal_zone occupancy is none')
|
||||||
|
@ -91,7 +91,7 @@ class TestGeometryFactory(TestCase):
|
||||||
|
|
||||||
def _test_hft(self, file):
|
def _test_hft(self, file):
|
||||||
_construction_keys = ['nrel']
|
_construction_keys = ['nrel']
|
||||||
_usage_keys = ['comnet', 'hft']
|
_usage_keys = ['comnet', 'nrcan']
|
||||||
for construction_key in _construction_keys:
|
for construction_key in _construction_keys:
|
||||||
for usage_key in _usage_keys:
|
for usage_key in _usage_keys:
|
||||||
# construction factory called first
|
# construction factory called first
|
||||||
|
|
Loading…
Reference in New Issue
Block a user