Compare commits
No commits in common. "main" and "v0.2.0.19" have entirely different histories.
@ -1,248 +0,0 @@
|
|||||||
"""
|
|
||||||
Cerc Idf exports one city or some buildings to idf format
|
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
||||||
Copyright © 2022 Concordia CERC group
|
|
||||||
Project Coder Guille Guillermo.GutierrezMorote@concordia.ca
|
|
||||||
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
|
||||||
Oriol Gavalda Torrellas oriol.gavalda@concordia.ca
|
|
||||||
"""
|
|
||||||
import copy
|
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
import hub.exports.building_energy.idf_helper as idf_cte
|
|
||||||
import hub.helpers.constants as cte
|
|
||||||
from hub.city_model_structure.attributes.schedule import Schedule
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_appliance import IdfAppliance
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_construction import IdfConstruction
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_dhw import IdfDhw
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_file_schedule import IdfFileSchedule
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_heating_system import IdfHeatingSystem
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_infiltration import IdfInfiltration
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_lighting import IdfLighting
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_material import IdfMaterial
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_occupancy import IdfOccupancy
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_schedule import IdfSchedule
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_shading import IdfShading
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_surfaces import IdfSurfaces
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_thermostat import IdfThermostat
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_ventilation import IdfVentilation
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_window import IdfWindow
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_windows_constructions import IdfWindowsConstructions
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_windows_material import IdfWindowsMaterial
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_zone import IdfZone
|
|
||||||
|
|
||||||
|
|
||||||
class CercIdf(IdfBase):
|
|
||||||
"""
|
|
||||||
Exports city to IDF
|
|
||||||
"""
|
|
||||||
|
|
||||||
_schedules_added_to_idf = {}
|
|
||||||
_materials_added_to_idf = {}
|
|
||||||
_windows_added_to_idf = {}
|
|
||||||
_constructions_added_to_idf = {}
|
|
||||||
_thermostat_added_to_idf = {}
|
|
||||||
|
|
||||||
def __init__(self, city, output_path, idf_file_path, idd_file_path, epw_file_path, target_buildings=None):
|
|
||||||
super().__init__(city, output_path, idf_file_path, idd_file_path, epw_file_path, target_buildings)
|
|
||||||
self._add_surfaces = IdfSurfaces.add
|
|
||||||
self._add_file_schedule = IdfFileSchedule.add
|
|
||||||
self._add_idf_schedule = IdfSchedule.add
|
|
||||||
self._add_construction = IdfConstruction.add
|
|
||||||
self._add_material = IdfMaterial.add
|
|
||||||
self._add_windows_material = IdfWindowsMaterial.add
|
|
||||||
self._add_windows_constructions = IdfWindowsConstructions.add
|
|
||||||
self._add_occupancy = IdfOccupancy.add
|
|
||||||
self._add_lighting = IdfLighting.add
|
|
||||||
self._add_appliance = IdfAppliance.add
|
|
||||||
self._add_infiltration = IdfInfiltration.add
|
|
||||||
self._add_infiltration_surface = IdfInfiltration.add_surface
|
|
||||||
self._add_ventilation = IdfVentilation.add
|
|
||||||
self._add_zone = IdfZone.add
|
|
||||||
self._add_thermostat = IdfThermostat.add
|
|
||||||
self._add_heating_system = IdfHeatingSystem.add
|
|
||||||
self._add_dhw = IdfDhw.add
|
|
||||||
self._add_shading = IdfShading.add
|
|
||||||
self._add_windows = IdfWindow.add
|
|
||||||
|
|
||||||
with open(self._idf_file_path, 'r', encoding='UTF-8') as base_idf:
|
|
||||||
lines = base_idf.readlines()
|
|
||||||
# Change city name
|
|
||||||
comment = f' !- Name'
|
|
||||||
field = f' Buildings in {self._city.name},'.ljust(26, ' ')
|
|
||||||
lines[15] = f'{field}{comment}\n'
|
|
||||||
with open(self._output_file_path, 'w', encoding='UTF-8') as self._idf_file:
|
|
||||||
self._idf_file.writelines(lines)
|
|
||||||
self._export()
|
|
||||||
|
|
||||||
def _create_geometry_rules(self):
|
|
||||||
file = self._files['constructions']
|
|
||||||
self._write_to_idf_format(file, idf_cte.GLOBAL_GEOMETRY_RULES)
|
|
||||||
self._write_to_idf_format(file, 'UpperLeftCorner', 'Starting Vertex Position')
|
|
||||||
self._write_to_idf_format(file, 'CounterClockWise', 'Vertex Entry Direction')
|
|
||||||
self._write_to_idf_format(file, 'World', 'Coordinate System', ';')
|
|
||||||
|
|
||||||
def _merge_files(self):
|
|
||||||
for file in self._files.values():
|
|
||||||
file.close()
|
|
||||||
for path in self._file_paths.values():
|
|
||||||
with open(path, 'r', encoding='UTF-8') as file:
|
|
||||||
lines = file.readlines()
|
|
||||||
self._idf_file.writelines(lines)
|
|
||||||
for path in self._file_paths.values():
|
|
||||||
os.unlink(path)
|
|
||||||
|
|
||||||
def _add_outputs(self):
|
|
||||||
with open(self._outputs_file_path, 'r', encoding='UTF-8') as base_idf:
|
|
||||||
lines = base_idf.readlines()
|
|
||||||
self._idf_file.writelines(lines)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _create_infiltration_schedules(thermal_zone):
|
|
||||||
_infiltration_schedules = []
|
|
||||||
if thermal_zone.thermal_control is None:
|
|
||||||
return []
|
|
||||||
for hvac_availability_schedule in thermal_zone.thermal_control.hvac_availability_schedules:
|
|
||||||
_schedule = Schedule()
|
|
||||||
_schedule.type = cte.INFILTRATION
|
|
||||||
_schedule.data_type = cte.FRACTION
|
|
||||||
_schedule.time_step = cte.HOUR
|
|
||||||
_schedule.time_range = cte.DAY
|
|
||||||
_schedule.day_types = copy.deepcopy(hvac_availability_schedule.day_types)
|
|
||||||
_infiltration_values = []
|
|
||||||
for hvac_value in hvac_availability_schedule.values:
|
|
||||||
if hvac_value == 0:
|
|
||||||
_infiltration_values.append(1.0)
|
|
||||||
else:
|
|
||||||
if thermal_zone.infiltration_rate_system_off == 0:
|
|
||||||
_infiltration_values.append(0.0)
|
|
||||||
else:
|
|
||||||
_infiltration_values.append(
|
|
||||||
thermal_zone.infiltration_rate_system_on / thermal_zone.infiltration_rate_system_off)
|
|
||||||
_schedule.values = _infiltration_values
|
|
||||||
_infiltration_schedules.append(_schedule)
|
|
||||||
return _infiltration_schedules
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _create_ventilation_schedules(thermal_zone):
|
|
||||||
_ventilation_schedules = []
|
|
||||||
if thermal_zone.thermal_control is None:
|
|
||||||
return []
|
|
||||||
for hvac_availability_schedule in thermal_zone.thermal_control.hvac_availability_schedules:
|
|
||||||
_schedule = Schedule()
|
|
||||||
_schedule.type = cte.VENTILATION
|
|
||||||
_schedule.data_type = cte.FRACTION
|
|
||||||
_schedule.time_step = cte.HOUR
|
|
||||||
_schedule.time_range = cte.DAY
|
|
||||||
_schedule.day_types = copy.deepcopy(hvac_availability_schedule.day_types)
|
|
||||||
_ventilation_schedules = thermal_zone.thermal_control.hvac_availability_schedules
|
|
||||||
return _ventilation_schedules
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _create_constant_value_schedules(value, amount):
|
|
||||||
_schedule = Schedule()
|
|
||||||
_schedule.type = ''
|
|
||||||
_schedule.data_type = cte.ANY_NUMBER
|
|
||||||
_schedule.time_step = cte.HOUR
|
|
||||||
_schedule.time_range = cte.DAY
|
|
||||||
_schedule.day_types = ['monday',
|
|
||||||
'tuesday',
|
|
||||||
'wednesday',
|
|
||||||
'thursday',
|
|
||||||
'friday',
|
|
||||||
'saturday',
|
|
||||||
'sunday',
|
|
||||||
'holiday',
|
|
||||||
'winter_design_day',
|
|
||||||
'summer_design_day']
|
|
||||||
_schedule.values = [value for _ in range(0, amount)]
|
|
||||||
return [_schedule]
|
|
||||||
|
|
||||||
def _export(self):
|
|
||||||
|
|
||||||
for building in self._city.buildings:
|
|
||||||
is_target = building.name in self._target_buildings or building.name in self._adjacent_buildings
|
|
||||||
for internal_zone in building.internal_zones:
|
|
||||||
if internal_zone.thermal_zones_from_internal_zones is None:
|
|
||||||
is_target = False
|
|
||||||
continue
|
|
||||||
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
|
|
||||||
if is_target:
|
|
||||||
service_temperature = thermal_zone.domestic_hot_water.service_temperature
|
|
||||||
usage = thermal_zone.usage_name
|
|
||||||
occ = thermal_zone.occupancy
|
|
||||||
if occ.occupancy_density == 0:
|
|
||||||
total_heat = 0
|
|
||||||
else:
|
|
||||||
total_heat = (
|
|
||||||
occ.sensible_convective_internal_gain +
|
|
||||||
occ.sensible_radiative_internal_gain +
|
|
||||||
occ.latent_internal_gain
|
|
||||||
) / occ.occupancy_density
|
|
||||||
self._add_idf_schedule(self, usage, 'Infiltration', self._create_infiltration_schedules(thermal_zone))
|
|
||||||
self._add_idf_schedule(self, usage, 'Ventilation', self._create_ventilation_schedules(thermal_zone))
|
|
||||||
self._add_idf_schedule(self, usage, 'Occupancy', thermal_zone.occupancy.occupancy_schedules)
|
|
||||||
self._add_idf_schedule(self, usage, 'HVAC AVAIL', thermal_zone.thermal_control.hvac_availability_schedules)
|
|
||||||
self._add_idf_schedule(self, usage, 'Heating thermostat',
|
|
||||||
thermal_zone.thermal_control.heating_set_point_schedules)
|
|
||||||
self._add_idf_schedule(self, usage, 'Cooling thermostat',
|
|
||||||
thermal_zone.thermal_control.cooling_set_point_schedules)
|
|
||||||
self._add_idf_schedule(self, usage, 'Lighting', thermal_zone.lighting.schedules)
|
|
||||||
self._add_idf_schedule(self, usage, 'Appliance', thermal_zone.appliances.schedules)
|
|
||||||
self._add_idf_schedule(self, usage, 'DHW_prof', thermal_zone.domestic_hot_water.schedules)
|
|
||||||
self._add_idf_schedule(self, usage, 'DHW_temp',
|
|
||||||
self._create_constant_value_schedules(service_temperature, 24))
|
|
||||||
self._add_idf_schedule(self, usage, 'Activity Level', self._create_constant_value_schedules(total_heat, 24))
|
|
||||||
self._add_file_schedule(self, usage, 'cold_temp',
|
|
||||||
self._create_constant_value_schedules(building.cold_water_temperature[cte.HOUR],
|
|
||||||
24))
|
|
||||||
for thermal_boundary in thermal_zone.thermal_boundaries:
|
|
||||||
self._add_material(self, thermal_boundary)
|
|
||||||
self._add_construction(self, thermal_boundary)
|
|
||||||
for thermal_opening in thermal_boundary.thermal_openings:
|
|
||||||
self._add_windows_material(self, thermal_boundary, thermal_opening)
|
|
||||||
self._add_windows_constructions(self, thermal_boundary)
|
|
||||||
self._add_zone(self, thermal_zone, building.name)
|
|
||||||
self._add_occupancy(self, thermal_zone, building.name)
|
|
||||||
self._add_lighting(self, thermal_zone, building.name)
|
|
||||||
self._add_appliance(self, thermal_zone, building.name)
|
|
||||||
if self._calculate_with_new_infiltration: # ToDo: Check with oriol if we want to keep the old method too
|
|
||||||
self._add_infiltration_surface(self, thermal_zone, building.name)
|
|
||||||
else:
|
|
||||||
self._add_infiltration(self, thermal_zone, building.name)
|
|
||||||
self._add_ventilation(self, thermal_zone, building.name)
|
|
||||||
self._add_thermostat(self, thermal_zone)
|
|
||||||
self._add_heating_system(self, thermal_zone, building.name)
|
|
||||||
self._add_dhw(self, thermal_zone, building.name)
|
|
||||||
if is_target:
|
|
||||||
self._add_surfaces(self, building, building.name)
|
|
||||||
self._add_windows(self, building)
|
|
||||||
else:
|
|
||||||
self._add_shading(self, building)
|
|
||||||
|
|
||||||
self._create_output_control_lighting() # Add lighting control to the lighting
|
|
||||||
|
|
||||||
# Create base values
|
|
||||||
self._create_geometry_rules()
|
|
||||||
|
|
||||||
# Merge files
|
|
||||||
self._merge_files()
|
|
||||||
self._add_outputs()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def _energy_plus(self):
|
|
||||||
return shutil.which('energyplus')
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
cmd = [self._energy_plus,
|
|
||||||
'--weather', self._epw_file_path,
|
|
||||||
'--output-directory', self._output_path,
|
|
||||||
'--idd', self._idd_file_path,
|
|
||||||
'--expandobjects',
|
|
||||||
'--readvars',
|
|
||||||
'--output-prefix', f'{self._city.name}_',
|
|
||||||
self._output_file_path]
|
|
||||||
subprocess.run(cmd, cwd=self._output_path)
|
|
@ -169,7 +169,7 @@ class EnergyAde:
|
|||||||
def _building_geometry(self, building, building_dic, city):
|
def _building_geometry(self, building, building_dic, city):
|
||||||
|
|
||||||
building_dic['bldg:Building']['bldg:function'] = building.function
|
building_dic['bldg:Building']['bldg:function'] = building.function
|
||||||
building_dic['bldg:Building']['bldg:usage'] = building.usages
|
building_dic['bldg:Building']['bldg:usage'] = building.usages_percentage
|
||||||
building_dic['bldg:Building']['bldg:yearOfConstruction'] = building.year_of_construction
|
building_dic['bldg:Building']['bldg:yearOfConstruction'] = building.year_of_construction
|
||||||
building_dic['bldg:Building']['bldg:roofType'] = building.roof_type
|
building_dic['bldg:Building']['bldg:roofType'] = building.roof_type
|
||||||
building_dic['bldg:Building']['bldg:measuredHeight'] = {
|
building_dic['bldg:Building']['bldg:measuredHeight'] = {
|
||||||
|
@ -8,12 +8,10 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord
|
|||||||
"""
|
"""
|
||||||
import copy
|
import copy
|
||||||
import datetime
|
import datetime
|
||||||
import shutil
|
import glob
|
||||||
import subprocess
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from geomeppy import IDF
|
from geomeppy import IDF
|
||||||
|
|
||||||
import hub.helpers.constants as cte
|
import hub.helpers.constants as cte
|
||||||
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.thermal_zone import ThermalZone
|
from hub.city_model_structure.building_demand.thermal_zone import ThermalZone
|
||||||
@ -109,7 +107,6 @@ class Idf:
|
|||||||
else:
|
else:
|
||||||
for building_name in target_buildings:
|
for building_name in target_buildings:
|
||||||
building = city.city_object(building_name)
|
building = city.city_object(building_name)
|
||||||
print('Name: ', building_name)
|
|
||||||
if building.neighbours is not None:
|
if building.neighbours is not None:
|
||||||
self._adjacent_buildings += building.neighbours
|
self._adjacent_buildings += building.neighbours
|
||||||
self._export()
|
self._export()
|
||||||
@ -447,7 +444,7 @@ class Idf:
|
|||||||
subcategory = f'ELECTRIC EQUIPMENT#{zone_name}#InteriorEquipment'
|
subcategory = f'ELECTRIC EQUIPMENT#{zone_name}#InteriorEquipment'
|
||||||
self._idf.newidfobject(self._APPLIANCES,
|
self._idf.newidfobject(self._APPLIANCES,
|
||||||
Fuel_Type=fuel_type,
|
Fuel_Type=fuel_type,
|
||||||
Name=zone_name,
|
Name=f'{zone_name}_appliance',
|
||||||
Zone_or_ZoneList_or_Space_or_SpaceList_Name=zone_name,
|
Zone_or_ZoneList_or_Space_or_SpaceList_Name=zone_name,
|
||||||
Schedule_Name=f'Appliance schedules {thermal_zone.usage_name}',
|
Schedule_Name=f'Appliance schedules {thermal_zone.usage_name}',
|
||||||
Design_Level_Calculation_Method=method,
|
Design_Level_Calculation_Method=method,
|
||||||
@ -504,7 +501,7 @@ class Idf:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def _rename_building(self, city_name):
|
def _rename_building(self, city_name):
|
||||||
name = str(city_name.encode("utf-8"))
|
name = str(str(city_name.encode("utf-8")))
|
||||||
for building in self._idf.idfobjects[self._BUILDING]:
|
for building in self._idf.idfobjects[self._BUILDING]:
|
||||||
building.Name = f'Buildings in {name}'
|
building.Name = f'Buildings in {name}'
|
||||||
building['Solar_Distribution'] = 'FullExterior'
|
building['Solar_Distribution'] = 'FullExterior'
|
||||||
@ -531,12 +528,11 @@ class Idf:
|
|||||||
self._remove_sizing_periods()
|
self._remove_sizing_periods()
|
||||||
self._rename_building(self._city.name)
|
self._rename_building(self._city.name)
|
||||||
self._lod = self._city.level_of_detail.geometry
|
self._lod = self._city.level_of_detail.geometry
|
||||||
is_target = False
|
|
||||||
for building in self._city.buildings:
|
for building in self._city.buildings:
|
||||||
is_target = building.name in self._target_buildings or building.name in self._adjacent_buildings
|
is_target = building.name in self._target_buildings or building.name in self._adjacent_buildings
|
||||||
for internal_zone in building.internal_zones:
|
for internal_zone in building.internal_zones:
|
||||||
if internal_zone.thermal_zones_from_internal_zones is None:
|
if internal_zone.thermal_zones_from_internal_zones is None:
|
||||||
self._target_buildings.remove(building.name)
|
self._target_buildings.remoidf_surface_typeve(building.name)
|
||||||
is_target = False
|
is_target = False
|
||||||
continue
|
continue
|
||||||
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
|
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
|
||||||
@ -590,7 +586,9 @@ class Idf:
|
|||||||
if self._export_type == "Surfaces":
|
if self._export_type == "Surfaces":
|
||||||
if is_target:
|
if is_target:
|
||||||
if building.thermal_zones_from_internal_zones is not None:
|
if building.thermal_zones_from_internal_zones is not None:
|
||||||
|
start = datetime.datetime.now()
|
||||||
self._add_surfaces(building, building.name)
|
self._add_surfaces(building, building.name)
|
||||||
|
print(f'add surfaces {datetime.datetime.now() - start}')
|
||||||
else:
|
else:
|
||||||
self._add_pure_geometry(building, building.name)
|
self._add_pure_geometry(building, building.name)
|
||||||
else:
|
else:
|
||||||
@ -653,26 +651,14 @@ class Idf:
|
|||||||
self._idf.removeidfobject(window)
|
self._idf.removeidfobject(window)
|
||||||
|
|
||||||
self._idf.saveas(str(self._output_file))
|
self._idf.saveas(str(self._output_file))
|
||||||
for building in self._city.buildings:
|
|
||||||
if self._export_type == "Surfaces":
|
|
||||||
if is_target and building.thermal_zones_from_internal_zones is not None:
|
|
||||||
self._add_surfaces(building, building.name)
|
|
||||||
return self._idf
|
return self._idf
|
||||||
|
|
||||||
@property
|
|
||||||
def _energy_plus(self):
|
|
||||||
return shutil.which('energyplus')
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
cmd = [self._energy_plus,
|
"""
|
||||||
'--weather', self._epw_file_path,
|
Start the energy plus simulation
|
||||||
'--output-directory', self._output_path,
|
"""
|
||||||
'--idd', self._idd_file_path,
|
self._idf.run(expandobjects=False, readvars=True, output_directory=self._output_path,
|
||||||
'--expandobjects',
|
output_prefix=f'{self._city.name}_')
|
||||||
'--readvars',
|
|
||||||
'--output-prefix', f'{self._city.name}_',
|
|
||||||
self._idf_file_path]
|
|
||||||
subprocess.run(cmd, cwd=self._output_path)
|
|
||||||
|
|
||||||
def _add_block(self, building):
|
def _add_block(self, building):
|
||||||
_points = self._matrix_to_2d_list(building.foot_print.coordinates)
|
_points = self._matrix_to_2d_list(building.foot_print.coordinates)
|
||||||
@ -775,11 +761,13 @@ class Idf:
|
|||||||
else:
|
else:
|
||||||
construction_name = f'{boundary.construction_name} {boundary.parent_surface.type}'
|
construction_name = f'{boundary.construction_name} {boundary.parent_surface.type}'
|
||||||
_kwargs['Construction_Name'] = construction_name
|
_kwargs['Construction_Name'] = construction_name
|
||||||
start = datetime.datetime.now()
|
|
||||||
surface = self._idf.newidfobject(self._SURFACE, **_kwargs)
|
surface = self._idf.newidfobject(self._SURFACE, **_kwargs)
|
||||||
|
|
||||||
coordinates = self._matrix_to_list(boundary.parent_surface.solid_polygon.coordinates,
|
coordinates = self._matrix_to_list(boundary.parent_surface.solid_polygon.coordinates,
|
||||||
self._city.lower_corner)
|
self._city.lower_corner)
|
||||||
surface.setcoords(coordinates)
|
surface.setcoords(coordinates)
|
||||||
|
|
||||||
if self._lod >= 3:
|
if self._lod >= 3:
|
||||||
for internal_zone in building.internal_zones:
|
for internal_zone in building.internal_zones:
|
||||||
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
|
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
|
||||||
|
@ -1,62 +0,0 @@
|
|||||||
!- Linux Line endings
|
|
||||||
|
|
||||||
Version,
|
|
||||||
24.1; !- Version Identifier
|
|
||||||
|
|
||||||
SimulationControl,
|
|
||||||
No, !- Do Zone Sizing Calculation
|
|
||||||
No, !- Do System Sizing Calculation
|
|
||||||
No, !- Do Plant Sizing Calculation
|
|
||||||
No, !- Run Simulation for Sizing Periods
|
|
||||||
Yes, !- Run Simulation for Weather File Run Periods
|
|
||||||
No, !- Do HVAC Sizing Simulation for Sizing Periods
|
|
||||||
1; !- Maximum Number of HVAC Sizing Simulation Passes
|
|
||||||
|
|
||||||
Building,
|
|
||||||
Buildings in #CITY#, !- Name
|
|
||||||
0, !- North Axis
|
|
||||||
Suburbs, !- Terrain
|
|
||||||
0.04, !- Loads Convergence Tolerance Value
|
|
||||||
0.4, !- Temperature Convergence Tolerance Value
|
|
||||||
FullExterior, !- Solar Distribution
|
|
||||||
25, !- Maximum Number of Warmup Days
|
|
||||||
6; !- Minimum Number of Warmup Days
|
|
||||||
|
|
||||||
Timestep,
|
|
||||||
4; !- Number of Timesteps per Hour
|
|
||||||
|
|
||||||
RunPeriod,
|
|
||||||
Run Period 1, !- Name
|
|
||||||
1, !- Begin Month
|
|
||||||
1, !- Begin Day of Month
|
|
||||||
, !- Begin Year
|
|
||||||
12, !- End Month
|
|
||||||
31, !- End Day of Month
|
|
||||||
, !- End Year
|
|
||||||
Tuesday, !- Day of Week for Start Day
|
|
||||||
Yes, !- Use Weather File Holidays and Special Days
|
|
||||||
Yes, !- Use Weather File Daylight Saving Period
|
|
||||||
No, !- Apply Weekend Holiday Rule
|
|
||||||
Yes, !- Use Weather File Rain Indicators
|
|
||||||
Yes; !- Use Weather File Snow Indicators
|
|
||||||
|
|
||||||
SCHEDULETYPELIMITS,
|
|
||||||
Any Number, !- Name
|
|
||||||
, !- Lower Limit Value
|
|
||||||
, !- Upper Limit Value
|
|
||||||
, !- Numeric Type
|
|
||||||
Dimensionless; !- Unit Type
|
|
||||||
|
|
||||||
SCHEDULETYPELIMITS,
|
|
||||||
Fraction, !- Name
|
|
||||||
0, !- Lower Limit Value
|
|
||||||
1, !- Upper Limit Value
|
|
||||||
Continuous, !- Numeric Type
|
|
||||||
Dimensionless; !- Unit Type
|
|
||||||
|
|
||||||
SCHEDULETYPELIMITS,
|
|
||||||
On/Off, !- Name
|
|
||||||
0, !- Lower Limit Value
|
|
||||||
1, !- Upper Limit Value
|
|
||||||
Discrete, !- Numeric Type
|
|
||||||
Dimensionless; !- Unit Type
|
|
@ -1,74 +0,0 @@
|
|||||||
|
|
||||||
Output:Table:SummaryReports,
|
|
||||||
AnnualBuildingUtilityPerformanceSummary, !- Report 1 Name
|
|
||||||
DemandEndUseComponentsSummary, !- Report 2 Name
|
|
||||||
SensibleHeatGainSummary, !- Report 3 Name
|
|
||||||
InputVerificationandResultsSummary, !- Report 4 Name
|
|
||||||
AdaptiveComfortSummary, !- Report 5 Name
|
|
||||||
Standard62.1Summary, !- Report 6 Name
|
|
||||||
ClimaticDataSummary, !- Report 7 Name
|
|
||||||
EquipmentSummary, !- Report 8 Name
|
|
||||||
EnvelopeSummary, !- Report 9 Name
|
|
||||||
LightingSummary, !- Report 10 Name
|
|
||||||
HVACSizingSummary, !- Report 11 Name
|
|
||||||
SystemSummary, !- Report 12 Name
|
|
||||||
ComponentSizingSummary, !- Report 13 Name
|
|
||||||
OutdoorAirSummary, !- Report 14 Name
|
|
||||||
ObjectCountSummary, !- Report 15 Name
|
|
||||||
EndUseEnergyConsumptionOtherFuelsMonthly, !- Report 16 Name
|
|
||||||
PeakEnergyEndUseOtherFuelsMonthly; !- Report 17 Name
|
|
||||||
|
|
||||||
OutputControl:Table:Style,
|
|
||||||
CommaAndHTML, !- Column Separator
|
|
||||||
JtoKWH; !- Unit Conversion
|
|
||||||
|
|
||||||
OUTPUT:VARIABLE,
|
|
||||||
*, !- Key Value
|
|
||||||
Zone Ideal Loads Supply Air Total Heating Energy, !- Variable Name
|
|
||||||
Hourly; !- Reporting Frequency
|
|
||||||
|
|
||||||
OUTPUT:VARIABLE,
|
|
||||||
*, !- Key Value
|
|
||||||
Zone Ideal Loads Supply Air Total Cooling Energy, !- Variable Name
|
|
||||||
Hourly; !- Reporting Frequency
|
|
||||||
|
|
||||||
OUTPUT:VARIABLE,
|
|
||||||
*, !- Key Value
|
|
||||||
Water Use Equipment Heating Rate, !- Variable Name
|
|
||||||
Hourly; !- Reporting Frequency
|
|
||||||
|
|
||||||
OUTPUT:VARIABLE,
|
|
||||||
*, !- Key Value
|
|
||||||
Zone Lights Electricity Rate, !- Variable Name
|
|
||||||
Hourly; !- Reporting Frequency
|
|
||||||
|
|
||||||
OUTPUT:VARIABLE,
|
|
||||||
*, !- Key Value
|
|
||||||
Other Equipment Electricity Rate, !- Variable Name
|
|
||||||
Hourly; !- Reporting Frequency
|
|
||||||
|
|
||||||
OUTPUT:VARIABLE,
|
|
||||||
*, !- Key Value
|
|
||||||
Zone Air Temperature, !- Variable Name
|
|
||||||
Hourly; !- Reporting Frequency
|
|
||||||
|
|
||||||
OUTPUT:VARIABLE,
|
|
||||||
*, !- Key Value
|
|
||||||
Zone Air Relative Humidity, !- Variable Name
|
|
||||||
Hourly; !- Reporting Frequency
|
|
||||||
|
|
||||||
Output:Meter,
|
|
||||||
DISTRICTHEATING:Facility, !- Key Name
|
|
||||||
hourly; !- Reporting Frequency
|
|
||||||
|
|
||||||
Output:Meter,
|
|
||||||
DISTRICTCOOLING:Facility, !- Key Name
|
|
||||||
hourly; !- Reporting Frequency
|
|
||||||
|
|
||||||
Output:Meter,
|
|
||||||
InteriorEquipment:Electricity, !- Key Name
|
|
||||||
hourly; !- Reporting Frequency
|
|
||||||
|
|
||||||
Output:Meter,
|
|
||||||
InteriorLights:Electricity, !- Key Name
|
|
||||||
hourly; !- Reporting Frequency
|
|
@ -1,60 +0,0 @@
|
|||||||
import hub.helpers.constants as cte
|
|
||||||
|
|
||||||
BUILDING_SURFACE = '\nBUILDINGSURFACE:DETAILED,\n'
|
|
||||||
WINDOW_SURFACE = '\nFENESTRATIONSURFACE:DETAILED,\n'
|
|
||||||
COMPACT_SCHEDULE = '\nSCHEDULE:COMPACT,\n'
|
|
||||||
FILE_SCHEDULE = '\nSCHEDULE:FILE,\n'
|
|
||||||
NOMASS_MATERIAL = '\nMATERIAL:NOMASS,\n'
|
|
||||||
SOLID_MATERIAL = '\nMATERIAL,\n'
|
|
||||||
WINDOW_MATERIAL = '\nWINDOWMATERIAL:SIMPLEGLAZINGSYSTEM,\n'
|
|
||||||
CONSTRUCTION = '\nCONSTRUCTION,\n'
|
|
||||||
ZONE = '\nZONE,\n'
|
|
||||||
GLOBAL_GEOMETRY_RULES = '\nGlobalGeometryRules,\n'
|
|
||||||
PEOPLE = '\nPEOPLE,\n'
|
|
||||||
LIGHTS = '\nLIGHTS,\n'
|
|
||||||
APPLIANCES = '\nOTHEREQUIPMENT,\n'
|
|
||||||
OUTPUT_CONTROL = '\nOutputControl:IlluminanceMap:Style,\n'
|
|
||||||
INFILTRATION = '\nZONEINFILTRATION:DESIGNFLOWRATE,\n'
|
|
||||||
VENTILATION = '\nZONEVENTILATION:DESIGNFLOWRATE,\n'
|
|
||||||
THERMOSTAT = '\nHVACTEMPLATE:THERMOSTAT,\n'
|
|
||||||
IDEAL_LOAD_SYSTEM = '\nHVACTEMPLATE:ZONE:IDEALLOADSAIRSYSTEM,\n'
|
|
||||||
DHW = '\nWATERUSE:EQUIPMENT,\n'
|
|
||||||
SHADING = '\nSHADING:BUILDING:DETAILED,\n'
|
|
||||||
|
|
||||||
AUTOCALCULATE = 'autocalculate'
|
|
||||||
ROUGHNESS = 'MediumRough'
|
|
||||||
OUTDOORS = 'Outdoors'
|
|
||||||
GROUND = 'Ground'
|
|
||||||
SURFACE = 'Surface'
|
|
||||||
SUN_EXPOSED = 'SunExposed'
|
|
||||||
WIND_EXPOSED = 'WindExposed'
|
|
||||||
NON_SUN_EXPOSED = 'NoSun'
|
|
||||||
NON_WIND_EXPOSED = 'NoWind'
|
|
||||||
EMPTY = ''
|
|
||||||
|
|
||||||
idf_surfaces_dictionary = {
|
|
||||||
cte.WALL: 'wall',
|
|
||||||
cte.GROUND: 'floor',
|
|
||||||
cte.ROOF: 'roof'
|
|
||||||
}
|
|
||||||
|
|
||||||
idf_type_limits = {
|
|
||||||
cte.ON_OFF: 'on/off',
|
|
||||||
cte.FRACTION: 'Fraction',
|
|
||||||
cte.ANY_NUMBER: 'Any Number',
|
|
||||||
cte.CONTINUOUS: 'Continuous',
|
|
||||||
cte.DISCRETE: 'Discrete'
|
|
||||||
}
|
|
||||||
|
|
||||||
idf_day_types = {
|
|
||||||
cte.MONDAY: 'Monday',
|
|
||||||
cte.TUESDAY: 'Tuesday',
|
|
||||||
cte.WEDNESDAY: 'Wednesday',
|
|
||||||
cte.THURSDAY: 'Thursday',
|
|
||||||
cte.FRIDAY: 'Friday',
|
|
||||||
cte.SATURDAY: 'Saturday',
|
|
||||||
cte.SUNDAY: 'Sunday',
|
|
||||||
cte.HOLIDAY: 'Holidays',
|
|
||||||
cte.WINTER_DESIGN_DAY: 'WinterDesignDay',
|
|
||||||
cte.SUMMER_DESIGN_DAY: 'SummerDesignDay'
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
import hub.exports.building_energy.idf_helper as idf_cte
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
|
|
||||||
|
|
||||||
|
|
||||||
class IdfAppliance(IdfBase):
|
|
||||||
@staticmethod
|
|
||||||
def add(self, thermal_zone, zone_name):
|
|
||||||
schedule_name = f'Appliance schedules {thermal_zone.usage_name}'
|
|
||||||
storeys_number = int(thermal_zone.total_floor_area / thermal_zone.footprint_area)
|
|
||||||
watts_per_zone_floor_area = thermal_zone.appliances.density * storeys_number
|
|
||||||
subcategory = f'ELECTRIC EQUIPMENT#{zone_name}#InteriorEquipment'
|
|
||||||
file = self._files['appliances']
|
|
||||||
self._write_to_idf_format(file, idf_cte.APPLIANCES)
|
|
||||||
self._write_to_idf_format(file, zone_name, 'Name')
|
|
||||||
self._write_to_idf_format(file, 'Electricity', 'Fuel Type')
|
|
||||||
self._write_to_idf_format(file, zone_name, 'Zone or ZoneList or Space or SpaceList Name')
|
|
||||||
self._write_to_idf_format(file, schedule_name, 'Schedule Name')
|
|
||||||
self._write_to_idf_format(file, 'Watts/Area', 'Design Level Calculation Method')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Design Level')
|
|
||||||
self._write_to_idf_format(file, watts_per_zone_floor_area, 'Power per Zone Floor Area')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Power per Person')
|
|
||||||
self._write_to_idf_format(file, thermal_zone.appliances.latent_fraction, 'Fraction Latent')
|
|
||||||
self._write_to_idf_format(file, thermal_zone.appliances.radiative_fraction, 'Fraction Radiant')
|
|
||||||
self._write_to_idf_format(file, 0, 'Fraction Lost')
|
|
||||||
self._write_to_idf_format(file, 0, 'Carbon Dioxide Generation Rate')
|
|
||||||
self._write_to_idf_format(file, subcategory, 'EndUse Subcategory', ';')
|
|
@ -1,78 +0,0 @@
|
|||||||
import os
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
import hub.exports.building_energy.idf_helper as idf_cte
|
|
||||||
|
|
||||||
|
|
||||||
class IdfBase:
|
|
||||||
def __init__(self, city, output_path, idf_file_path, idd_file_path, epw_file_path, target_buildings=None,
|
|
||||||
_calculate_with_new_infiltration=True):
|
|
||||||
self._city = city
|
|
||||||
self._output_path = str(output_path.resolve())
|
|
||||||
self._output_file_path = str((output_path / f'{city.name}.idf').resolve())
|
|
||||||
|
|
||||||
self._file_paths = {
|
|
||||||
'schedules': str((output_path / 'schedules.idf').resolve()),
|
|
||||||
'file_schedules': str((output_path / 'file_schedules.idf').resolve()),
|
|
||||||
'solid_materials': str((output_path / 'solid_materials.idf').resolve()),
|
|
||||||
'nomass_materials': str((output_path / 'nomass_materials.idf').resolve()),
|
|
||||||
'window_materials': str((output_path / 'window_materials.idf').resolve()),
|
|
||||||
'constructions': str((output_path / 'constructions.idf').resolve()),
|
|
||||||
'zones': str((output_path / 'zones.idf').resolve()),
|
|
||||||
'surfaces': str((output_path / 'surfaces.idf').resolve()),
|
|
||||||
'fenestration': str((output_path / 'fenestration.idf').resolve()),
|
|
||||||
'occupancy': str((output_path / 'occupancy.idf').resolve()),
|
|
||||||
'lighting': str((output_path / 'lights.idf').resolve()),
|
|
||||||
'appliances': str((output_path / 'appliances.idf').resolve()),
|
|
||||||
'shading': str((output_path / 'shading.idf').resolve()),
|
|
||||||
'infiltration': str((output_path / 'infiltration.idf').resolve()),
|
|
||||||
'ventilation': str((output_path / 'ventilation.idf').resolve()),
|
|
||||||
'thermostat': str((output_path / 'thermostat.idf').resolve()),
|
|
||||||
'ideal_load_system': str((output_path / 'ideal_load_system.idf').resolve()),
|
|
||||||
'dhw': str((output_path / 'dhw.idf').resolve()),
|
|
||||||
}
|
|
||||||
self._files = {}
|
|
||||||
for key, value in self._file_paths.items():
|
|
||||||
self._files[key] = open(value, 'w', encoding='UTF-8')
|
|
||||||
|
|
||||||
self._idd_file_path = str(idd_file_path)
|
|
||||||
self._idf_file_path = str(idf_file_path)
|
|
||||||
self._outputs_file_path = str(Path(idf_file_path).parent / 'outputs.idf')
|
|
||||||
self._epw_file_path = str(epw_file_path)
|
|
||||||
|
|
||||||
self._target_buildings = target_buildings
|
|
||||||
self._adjacent_buildings = []
|
|
||||||
|
|
||||||
if target_buildings is None:
|
|
||||||
self._target_buildings = [building.name for building in self._city.buildings]
|
|
||||||
else:
|
|
||||||
for building_name in target_buildings:
|
|
||||||
building = city.city_object(building_name)
|
|
||||||
if building.neighbours is not None:
|
|
||||||
self._adjacent_buildings += building.neighbours
|
|
||||||
self._calculate_with_new_infiltration = _calculate_with_new_infiltration
|
|
||||||
|
|
||||||
def _create_output_control_lighting(self):
|
|
||||||
file = self._files['appliances']
|
|
||||||
self._write_to_idf_format(file, idf_cte.OUTPUT_CONTROL)
|
|
||||||
self._write_to_idf_format(file, 'Comma', 'Column Separator', ';')
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _write_to_idf_format(file, field, comment='', eol=','):
|
|
||||||
if comment != '':
|
|
||||||
comment = f' !- {comment}'
|
|
||||||
field = f' {field}{eol}'.ljust(26, ' ')
|
|
||||||
file.write(f'{field}{comment}\n')
|
|
||||||
else:
|
|
||||||
file.write(f'{field}{comment}')
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _matrix_to_list(points, lower_corner):
|
|
||||||
lower_x = lower_corner[0]
|
|
||||||
lower_y = lower_corner[1]
|
|
||||||
lower_z = lower_corner[2]
|
|
||||||
points_list = []
|
|
||||||
for point in points:
|
|
||||||
point_tuple = (point[0] - lower_x, point[1] - lower_y, point[2] - lower_z)
|
|
||||||
points_list.append(point_tuple)
|
|
||||||
return points_list
|
|
@ -1,56 +0,0 @@
|
|||||||
import hub.exports.building_energy.idf_helper as idf_cte
|
|
||||||
from hub.city_model_structure.building_demand.layer import Layer
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
|
|
||||||
|
|
||||||
|
|
||||||
class IdfConstruction(IdfBase):
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _add_solid_material(self, layer):
|
|
||||||
file = self._files['solid_materials']
|
|
||||||
self._write_to_idf_format(file, idf_cte.SOLID_MATERIAL)
|
|
||||||
self._write_to_idf_format(file, layer.material_name, 'Name')
|
|
||||||
self._write_to_idf_format(file, idf_cte.ROUGHNESS, 'Roughness')
|
|
||||||
self._write_to_idf_format(file, layer.thickness, 'Thickness')
|
|
||||||
self._write_to_idf_format(file, layer.conductivity, 'Conductivity')
|
|
||||||
self._write_to_idf_format(file, layer.density, 'Density')
|
|
||||||
self._write_to_idf_format(file, layer.specific_heat, 'Specific Heat')
|
|
||||||
self._write_to_idf_format(file, layer.thermal_absorptance, 'Thermal Absorptance')
|
|
||||||
self._write_to_idf_format(file, layer.solar_absorptance, 'Solar Absorptance')
|
|
||||||
self._write_to_idf_format(file, layer.visible_absorptance, 'Visible Absorptance', ';')
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _add_default_material(self):
|
|
||||||
layer = Layer()
|
|
||||||
layer.material_name = 'DefaultMaterial'
|
|
||||||
layer.thickness = 0.1
|
|
||||||
layer.conductivity = 0.1
|
|
||||||
layer.density = 1000
|
|
||||||
layer.specific_heat = 1000
|
|
||||||
layer.thermal_absorptance = 0.9
|
|
||||||
layer.solar_absorptance = 0.9
|
|
||||||
layer.visible_absorptance = 0.7
|
|
||||||
IdfConstruction._add_solid_material(self, layer)
|
|
||||||
return layer
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def add(self, thermal_boundary):
|
|
||||||
if thermal_boundary.layers is None:
|
|
||||||
thermal_boundary.layers = [IdfConstruction._add_default_material(self)]
|
|
||||||
name = f'{thermal_boundary.construction_name} {thermal_boundary.parent_surface.type}'
|
|
||||||
|
|
||||||
if name not in self._constructions_added_to_idf:
|
|
||||||
self._constructions_added_to_idf[name] = True
|
|
||||||
file = self._files['constructions']
|
|
||||||
self._write_to_idf_format(file, idf_cte.CONSTRUCTION)
|
|
||||||
self._write_to_idf_format(file, name, 'Name')
|
|
||||||
eol = ','
|
|
||||||
if len(thermal_boundary.layers) == 1:
|
|
||||||
eol = ';'
|
|
||||||
self._write_to_idf_format(file, thermal_boundary.layers[0].material_name, 'Outside Layer', eol)
|
|
||||||
for i in range(1, len(thermal_boundary.layers) - 1):
|
|
||||||
comment = f'Layer {i + 1}'
|
|
||||||
material_name = thermal_boundary.layers[i].material_name
|
|
||||||
if i == len(thermal_boundary.layers) - 2:
|
|
||||||
eol = ';'
|
|
||||||
self._write_to_idf_format(file, material_name, comment, eol)
|
|
@ -1,21 +0,0 @@
|
|||||||
import hub.exports.building_energy.idf_helper as idf_cte
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
|
|
||||||
|
|
||||||
|
|
||||||
class IdfDhw(IdfBase):
|
|
||||||
@staticmethod
|
|
||||||
def add(self, thermal_zone, zone_name):
|
|
||||||
peak_flow_rate = thermal_zone.domestic_hot_water.peak_flow * thermal_zone.total_floor_area
|
|
||||||
flow_rate_schedule = f'DHW_prof schedules {thermal_zone.usage_name}'
|
|
||||||
dhw_schedule = f'DHW_temp schedules {thermal_zone.usage_name}'
|
|
||||||
cold_temp_schedule = f'cold_temp schedules {thermal_zone.usage_name}'
|
|
||||||
file = self._files['dhw']
|
|
||||||
self._write_to_idf_format(file, idf_cte.DHW)
|
|
||||||
self._write_to_idf_format(file, zone_name, 'Name')
|
|
||||||
self._write_to_idf_format(file, zone_name, 'EndUse Subcategory')
|
|
||||||
self._write_to_idf_format(file, peak_flow_rate, 'Peak Flow Rate')
|
|
||||||
self._write_to_idf_format(file, flow_rate_schedule, 'Flow Rate Fraction Schedule Name')
|
|
||||||
self._write_to_idf_format(file, dhw_schedule, 'Target Temperature Schedule Name')
|
|
||||||
self._write_to_idf_format(file, dhw_schedule, 'Hot Water Supply Temperature Schedule Name')
|
|
||||||
self._write_to_idf_format(file, cold_temp_schedule, 'Cold Water Supply Temperature Schedule Name')
|
|
||||||
self._write_to_idf_format(file, zone_name, 'Zone Name', ';')
|
|
@ -1,30 +0,0 @@
|
|||||||
from pathlib import Path
|
|
||||||
import hub.helpers.constants as cte
|
|
||||||
import hub.exports.building_energy.idf_helper as idf_cte
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
|
|
||||||
|
|
||||||
|
|
||||||
class IdfFileSchedule(IdfBase):
|
|
||||||
@staticmethod
|
|
||||||
def add(self, usage, schedule_type, schedules):
|
|
||||||
schedule_name = f'{schedule_type} schedules {usage}'
|
|
||||||
for schedule in schedules:
|
|
||||||
if schedule_name not in self._schedules_added_to_idf:
|
|
||||||
self._schedules_added_to_idf[schedule_name] = True
|
|
||||||
file_name = str(
|
|
||||||
(Path(self._output_path) / f'{schedule_type} schedules {usage.replace("/", "_")}.csv').resolve())
|
|
||||||
with open(file_name, 'w', encoding='utf8') as file:
|
|
||||||
for value in schedule.values[0]:
|
|
||||||
file.write(f'{value},\n')
|
|
||||||
file = self._files['file_schedules']
|
|
||||||
self._write_to_idf_format(file, idf_cte.FILE_SCHEDULE)
|
|
||||||
self._write_to_idf_format(file, schedule_name, 'Name')
|
|
||||||
self._write_to_idf_format(file, idf_cte.idf_type_limits[schedule.data_type], 'Schedule Type Limits Name')
|
|
||||||
self._write_to_idf_format(file, Path(file_name).name, 'File Name')
|
|
||||||
self._write_to_idf_format(file, 1, 'Column Number')
|
|
||||||
self._write_to_idf_format(file, 0, 'Rows to Skip at Top')
|
|
||||||
self._write_to_idf_format(file, 8760, 'Number of Hours of Data')
|
|
||||||
self._write_to_idf_format(file, 'Comma', 'Column Separator')
|
|
||||||
self._write_to_idf_format(file, 'No', 'Interpolate to Timestep')
|
|
||||||
self._write_to_idf_format(file, '60', 'Minutes per Item')
|
|
||||||
self._write_to_idf_format(file, 'Yes', 'Adjust Schedule for Daylight Savings', ';')
|
|
@ -1,41 +0,0 @@
|
|||||||
import hub.exports.building_energy.idf_helper as idf_cte
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
|
|
||||||
|
|
||||||
|
|
||||||
class IdfHeatingSystem(IdfBase):
|
|
||||||
@staticmethod
|
|
||||||
def add(self, thermal_zone, zone_name):
|
|
||||||
availability_schedule = f'HVAC AVAIL SCHEDULES {thermal_zone.usage_name}'
|
|
||||||
thermostat_name = f'Thermostat {thermal_zone.usage_name}'
|
|
||||||
file = self._files['ideal_load_system']
|
|
||||||
self._write_to_idf_format(file, idf_cte.IDEAL_LOAD_SYSTEM)
|
|
||||||
self._write_to_idf_format(file, zone_name, 'Zone Name')
|
|
||||||
self._write_to_idf_format(file, thermostat_name, 'Template Thermostat Name')
|
|
||||||
self._write_to_idf_format(file, availability_schedule, 'System Availability Schedule Name')
|
|
||||||
self._write_to_idf_format(file, 50, 'Maximum Heating Supply Air Temperature')
|
|
||||||
self._write_to_idf_format(file, 13, 'Minimum Cooling Supply Air Temperature')
|
|
||||||
self._write_to_idf_format(file, 0.0156, 'Maximum Heating Supply Air Humidity Ratio')
|
|
||||||
self._write_to_idf_format(file, 0.0077, 'Minimum Cooling Supply Air Humidity Ratio')
|
|
||||||
self._write_to_idf_format(file, 'NoLimit', 'Heating Limit')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Maximum Heating Air Flow Rate')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Maximum Sensible Heating Capacity')
|
|
||||||
self._write_to_idf_format(file, 'NoLimit', 'Cooling Limit')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Maximum Cooling Air Flow Rate')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Maximum Total Cooling Capacity')
|
|
||||||
self._write_to_idf_format(file, availability_schedule, 'Heating Availability Schedule Name')
|
|
||||||
self._write_to_idf_format(file, availability_schedule, 'Cooling Availability Schedule Name')
|
|
||||||
self._write_to_idf_format(file, 'ConstantSensibleHeatRatio', 'Dehumidification Control Type')
|
|
||||||
self._write_to_idf_format(file, 0.7, 'Cooling Sensible Heat Ratio')
|
|
||||||
self._write_to_idf_format(file, 60, 'Dehumidification Setpoint')
|
|
||||||
self._write_to_idf_format(file, 'None', 'Humidification Control Type')
|
|
||||||
self._write_to_idf_format(file, 30, 'Humidification Setpoint')
|
|
||||||
self._write_to_idf_format(file, 'None', 'Outdoor Air Method')
|
|
||||||
self._write_to_idf_format(file, 0.00944, 'Outdoor Air Flow Rate per Person')
|
|
||||||
self._write_to_idf_format(file, 0.0, 'Outdoor Air Flow Rate per Zone Floor Area')
|
|
||||||
self._write_to_idf_format(file, 0, 'Outdoor Air Flow Rate per Zone')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Design Specification Outdoor Air Object Name')
|
|
||||||
self._write_to_idf_format(file, 'None', 'Demand Controlled Ventilation Type')
|
|
||||||
self._write_to_idf_format(file, 'NoEconomizer', 'Outdoor Air Economizer Type')
|
|
||||||
self._write_to_idf_format(file, 'None', 'Heat Recovery Type')
|
|
||||||
self._write_to_idf_format(file, 0.70, 'Sensible Heat Recovery Effectiveness')
|
|
||||||
self._write_to_idf_format(file, 0.65, 'Latent Heat Recovery Effectiveness', ';')
|
|
@ -1,32 +0,0 @@
|
|||||||
import hub.exports.building_energy.idf_helper as idf_cte
|
|
||||||
import hub.helpers.constants as cte
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
|
|
||||||
|
|
||||||
|
|
||||||
class IdfInfiltration(IdfBase):
|
|
||||||
@staticmethod
|
|
||||||
def add(self, thermal_zone, zone_name):
|
|
||||||
IdfInfiltration._add_infiltration(self, thermal_zone, zone_name, 'AirChanges/Hour', cte.HOUR_TO_SECONDS)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def add_surface(self, thermal_zone, zone_name):
|
|
||||||
IdfInfiltration._add_infiltration(self, thermal_zone, zone_name, 'Flow/ExteriorWallArea', cte.INFILTRATION_75PA_TO_4PA)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _add_infiltration(self, thermal_zone, zone_name, calculation_method, multiplier):
|
|
||||||
schedule_name = f'Infiltration schedules {thermal_zone.usage_name}'
|
|
||||||
infiltration = thermal_zone.infiltration_rate_system_off * multiplier
|
|
||||||
file = self._files['infiltration']
|
|
||||||
self._write_to_idf_format(file, idf_cte.INFILTRATION)
|
|
||||||
self._write_to_idf_format(file, zone_name, 'Name')
|
|
||||||
self._write_to_idf_format(file, zone_name, 'Zone or ZoneList or Space or SpaceList Name')
|
|
||||||
self._write_to_idf_format(file, schedule_name, 'Schedule Name')
|
|
||||||
self._write_to_idf_format(file, calculation_method, 'Design Flow Rate Calculation Method')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Design Flow Rate')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Flow Rate per Floor Area')
|
|
||||||
self._write_to_idf_format(file, infiltration, 'Flow Rate per Exterior Surface Area')
|
|
||||||
self._write_to_idf_format(file, infiltration, 'Air Changes per Hour')
|
|
||||||
self._write_to_idf_format(file, 1, 'Constant Term Coefficient')
|
|
||||||
self._write_to_idf_format(file, 0, 'Temperature Term Coefficient')
|
|
||||||
self._write_to_idf_format(file, 0, 'Velocity Term Coefficient')
|
|
||||||
self._write_to_idf_format(file, 0, 'Velocity Squared Term Coefficient', ';')
|
|
@ -1,28 +0,0 @@
|
|||||||
import hub.exports.building_energy.idf_helper as idf_cte
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
|
|
||||||
|
|
||||||
|
|
||||||
class IdfLighting(IdfBase):
|
|
||||||
@staticmethod
|
|
||||||
def add(self, thermal_zone, zone_name):
|
|
||||||
storeys_number = int(thermal_zone.total_floor_area / thermal_zone.footprint_area)
|
|
||||||
watts_per_zone_floor_area = thermal_zone.lighting.density * storeys_number
|
|
||||||
subcategory = f'ELECTRIC EQUIPMENT#{zone_name}#GeneralLights'
|
|
||||||
schedule_name = f'Lighting schedules {thermal_zone.usage_name}'
|
|
||||||
file = self._files['lighting']
|
|
||||||
self._write_to_idf_format(file, idf_cte.LIGHTS)
|
|
||||||
self._write_to_idf_format(file, f'{zone_name}_lights', 'Name')
|
|
||||||
self._write_to_idf_format(file, zone_name, 'Zone or ZoneList or Space or SpaceList Name')
|
|
||||||
self._write_to_idf_format(file, schedule_name, 'Schedule Name')
|
|
||||||
self._write_to_idf_format(file, 'Watts/Area', 'Design Level Calculation Method')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Lighting Level')
|
|
||||||
self._write_to_idf_format(file, watts_per_zone_floor_area, 'Watts per Zone Floor Area')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Watts per Person')
|
|
||||||
self._write_to_idf_format(file, 0, 'Return Air Fraction')
|
|
||||||
self._write_to_idf_format(file, thermal_zone.lighting.radiative_fraction, 'Fraction Radiant')
|
|
||||||
self._write_to_idf_format(file, 0, 'Fraction Visible')
|
|
||||||
self._write_to_idf_format(file, 1, 'Fraction Replaceable')
|
|
||||||
self._write_to_idf_format(file, subcategory, 'EndUse Subcategory')
|
|
||||||
self._write_to_idf_format(file, 'No', 'Return Air Fraction Calculated from Plenum Temperature')
|
|
||||||
self._write_to_idf_format(file, 0, 'Return Air Fraction Function of Plenum Temperature Coefficient 1')
|
|
||||||
self._write_to_idf_format(file, 0, 'Return Air Fraction Function of Plenum Temperature Coefficient 2', ';')
|
|
@ -1,39 +0,0 @@
|
|||||||
import hub.exports.building_energy.idf_helper as idf_cte
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
|
|
||||||
|
|
||||||
|
|
||||||
class IdfMaterial(IdfBase):
|
|
||||||
@staticmethod
|
|
||||||
def _add_solid_material(self, layer):
|
|
||||||
file = self._files['solid_materials']
|
|
||||||
self._write_to_idf_format(file, idf_cte.SOLID_MATERIAL)
|
|
||||||
self._write_to_idf_format(file, layer.material_name, 'Name')
|
|
||||||
self._write_to_idf_format(file, idf_cte.ROUGHNESS, 'Roughness')
|
|
||||||
self._write_to_idf_format(file, layer.thickness, 'Thickness')
|
|
||||||
self._write_to_idf_format(file, layer.conductivity, 'Conductivity')
|
|
||||||
self._write_to_idf_format(file, layer.density, 'Density')
|
|
||||||
self._write_to_idf_format(file, layer.specific_heat, 'Specific Heat')
|
|
||||||
self._write_to_idf_format(file, layer.thermal_absorptance, 'Thermal Absorptance')
|
|
||||||
self._write_to_idf_format(file, layer.solar_absorptance, 'Solar Absorptance')
|
|
||||||
self._write_to_idf_format(file, layer.visible_absorptance, 'Visible Absorptance', ';')
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _add_nomass_material(self, layer):
|
|
||||||
file = self._files['nomass_materials']
|
|
||||||
self._write_to_idf_format(file, idf_cte.NOMASS_MATERIAL)
|
|
||||||
self._write_to_idf_format(file, layer.material_name, 'Name')
|
|
||||||
self._write_to_idf_format(file, idf_cte.ROUGHNESS, 'Roughness')
|
|
||||||
self._write_to_idf_format(file, layer.thermal_resistance, 'Thermal Resistance')
|
|
||||||
self._write_to_idf_format(file, 0.9, 'Thermal Absorptance')
|
|
||||||
self._write_to_idf_format(file, 0.7, 'Solar Absorptance')
|
|
||||||
self._write_to_idf_format(file, 0.7, 'Visible Absorptance', ';')
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def add(self, thermal_boundary):
|
|
||||||
for layer in thermal_boundary.layers:
|
|
||||||
if layer.material_name not in self._materials_added_to_idf:
|
|
||||||
self._materials_added_to_idf[layer.material_name] = True
|
|
||||||
if layer.no_mass:
|
|
||||||
IdfMaterial._add_nomass_material(self, layer)
|
|
||||||
else:
|
|
||||||
IdfMaterial._add_solid_material(self, layer)
|
|
@ -1,47 +0,0 @@
|
|||||||
import hub.exports.building_energy.idf_helper as idf_cte
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
|
|
||||||
|
|
||||||
|
|
||||||
class IdfOccupancy(IdfBase):
|
|
||||||
@staticmethod
|
|
||||||
def add(self, thermal_zone, zone_name):
|
|
||||||
number_of_people = thermal_zone.occupancy.occupancy_density * thermal_zone.total_floor_area
|
|
||||||
fraction_radiant = 0
|
|
||||||
total_sensible = (
|
|
||||||
thermal_zone.occupancy.sensible_radiative_internal_gain + thermal_zone.occupancy.sensible_convective_internal_gain
|
|
||||||
)
|
|
||||||
if total_sensible != 0:
|
|
||||||
fraction_radiant = thermal_zone.occupancy.sensible_radiative_internal_gain / total_sensible
|
|
||||||
occupancy_schedule = f'Occupancy schedules {thermal_zone.usage_name}'
|
|
||||||
activity_level_schedule = f'Activity Level schedules {thermal_zone.usage_name}'
|
|
||||||
file = self._files['occupancy']
|
|
||||||
self._write_to_idf_format(file, idf_cte.PEOPLE)
|
|
||||||
self._write_to_idf_format(file, f'{zone_name}_occupancy', 'Name')
|
|
||||||
self._write_to_idf_format(file, zone_name, 'Zone or ZoneList or Space or SpaceList Name')
|
|
||||||
self._write_to_idf_format(file, occupancy_schedule, 'Number of People Schedule Name')
|
|
||||||
self._write_to_idf_format(file, 'People', 'Number of People Calculation Method')
|
|
||||||
self._write_to_idf_format(file, number_of_people, 'Number of People')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'People per Floor Area')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Floor Area per Person')
|
|
||||||
self._write_to_idf_format(file, fraction_radiant, 'Fraction Radiant')
|
|
||||||
self._write_to_idf_format(file, idf_cte.AUTOCALCULATE, 'Sensible Heat Fraction')
|
|
||||||
self._write_to_idf_format(file, activity_level_schedule, 'Activity Level Schedule Name')
|
|
||||||
self._write_to_idf_format(file, '3.82e-08', 'Carbon Dioxide Generation Rate')
|
|
||||||
self._write_to_idf_format(file, 'No', 'Enable ASHRAE 55 Comfort Warnings')
|
|
||||||
self._write_to_idf_format(file, 'EnclosureAveraged', 'Mean Radiant Temperature Calculation Type')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Surface NameAngle Factor List Name')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Work Efficiency Schedule Name')
|
|
||||||
self._write_to_idf_format(file, 'ClothingInsulationSchedule', 'Clothing Insulation Calculation Method')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Clothing Insulation Calculation Method Schedule Name')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Clothing Insulation Schedule Name')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Air Velocity Schedule Name')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Thermal Comfort Model 1 Type')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Thermal Comfort Model 2 Type')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Thermal Comfort Model 3 Type')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Thermal Comfort Model 4 Type')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Thermal Comfort Model 5 Type')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Thermal Comfort Model 6 Type')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Thermal Comfort Model 7 Type')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Ankle Level Air Velocity Schedule Name')
|
|
||||||
self._write_to_idf_format(file, '15.56', 'Cold Stress Temperature Threshold')
|
|
||||||
self._write_to_idf_format(file, '30', 'Heat Stress Temperature Threshold', ';')
|
|
@ -1,30 +0,0 @@
|
|||||||
import hub.exports.building_energy.idf_helper as idf_cte
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
|
|
||||||
|
|
||||||
|
|
||||||
class IdfSchedule(IdfBase):
|
|
||||||
@staticmethod
|
|
||||||
def add(self, usage, schedule_type, schedules):
|
|
||||||
if len(schedules) < 1:
|
|
||||||
return
|
|
||||||
schedule_name = f'{schedule_type} schedules {usage}'
|
|
||||||
if schedule_name not in self._schedules_added_to_idf:
|
|
||||||
self._schedules_added_to_idf[schedule_name] = True
|
|
||||||
file = self._files['schedules']
|
|
||||||
self._write_to_idf_format(file, idf_cte.COMPACT_SCHEDULE)
|
|
||||||
self._write_to_idf_format(file, schedule_name, 'Name')
|
|
||||||
self._write_to_idf_format(file, idf_cte.idf_type_limits[schedules[0].data_type], 'Schedule Type Limits Name')
|
|
||||||
self._write_to_idf_format(file, 'Through: 12/31', 'Field 1')
|
|
||||||
counter = 1
|
|
||||||
for j, schedule in enumerate(schedules):
|
|
||||||
_val = schedule.values
|
|
||||||
_new_field = ''
|
|
||||||
for day_type in schedule.day_types:
|
|
||||||
_new_field += f' {idf_cte.idf_day_types[day_type]}'
|
|
||||||
self._write_to_idf_format(file, f'For:{_new_field}', f'Field {j * 25 + 2}')
|
|
||||||
counter += 1
|
|
||||||
for i, _ in enumerate(_val):
|
|
||||||
self._write_to_idf_format(file, f'Until: {i + 1:02d}:00,{_val[i]}', f'Field {j * 25 + 3 + i}')
|
|
||||||
counter += 1
|
|
||||||
self._write_to_idf_format(file, 'For AllOtherDays', f'Field {counter + 1}')
|
|
||||||
self._write_to_idf_format(file, 'Until: 24:00,0.0', f'Field {counter + 2}', ';')
|
|
@ -1,25 +0,0 @@
|
|||||||
import hub.exports.building_energy.idf_helper as idf_cte
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
|
|
||||||
|
|
||||||
|
|
||||||
class IdfShading(IdfBase):
|
|
||||||
@staticmethod
|
|
||||||
def add(self, building):
|
|
||||||
name = building.name
|
|
||||||
file = self._files['shading']
|
|
||||||
for s, surface in enumerate(building.surfaces):
|
|
||||||
|
|
||||||
self._write_to_idf_format(file, idf_cte.SHADING)
|
|
||||||
self._write_to_idf_format(file, f'{name}_{s}', 'Name')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Transmittance Schedule Name')
|
|
||||||
self._write_to_idf_format(file, idf_cte.AUTOCALCULATE, 'Number of Vertices')
|
|
||||||
eol = ','
|
|
||||||
coordinates = self._matrix_to_list(surface.solid_polygon.coordinates, self._city.lower_corner)
|
|
||||||
coordinates_length = len(coordinates)
|
|
||||||
for i, coordinate in enumerate(coordinates):
|
|
||||||
vertex = i + 1
|
|
||||||
if vertex == coordinates_length:
|
|
||||||
eol = ';'
|
|
||||||
self._write_to_idf_format(file, coordinate[0], f'Vertex {vertex} Xcoordinate')
|
|
||||||
self._write_to_idf_format(file, coordinate[1], f'Vertex {vertex} Ycoordinate')
|
|
||||||
self._write_to_idf_format(file, coordinate[2], f'Vertex {vertex} Zcoordinate', eol)
|
|
@ -1,52 +0,0 @@
|
|||||||
import hub.exports.building_energy.idf_helper as idf_cte
|
|
||||||
import hub.helpers.constants as cte
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
|
|
||||||
|
|
||||||
|
|
||||||
class IdfSurfaces(IdfBase):
|
|
||||||
@staticmethod
|
|
||||||
def add(self, building, zone_name):
|
|
||||||
zone_name = f'{zone_name}'
|
|
||||||
file = self._files['surfaces']
|
|
||||||
for thermal_zone in building.thermal_zones_from_internal_zones:
|
|
||||||
for index, boundary in enumerate(thermal_zone.thermal_boundaries):
|
|
||||||
surface_type = idf_cte.idf_surfaces_dictionary[boundary.parent_surface.type]
|
|
||||||
outside_boundary_condition = idf_cte.OUTDOORS
|
|
||||||
sun_exposure = idf_cte.SUN_EXPOSED
|
|
||||||
wind_exposure = idf_cte.WIND_EXPOSED
|
|
||||||
outside_boundary_condition_object = idf_cte.EMPTY
|
|
||||||
name = f'Building_{building.name}_surface_{index}'
|
|
||||||
construction_name = f'{boundary.construction_name} {boundary.parent_surface.type}'
|
|
||||||
space_name = idf_cte.EMPTY
|
|
||||||
if boundary.parent_surface.type == cte.GROUND:
|
|
||||||
outside_boundary_condition = idf_cte.GROUND
|
|
||||||
sun_exposure = idf_cte.NON_SUN_EXPOSED
|
|
||||||
wind_exposure = idf_cte.NON_WIND_EXPOSED
|
|
||||||
if boundary.parent_surface.percentage_shared is not None and boundary.parent_surface.percentage_shared > 0.5:
|
|
||||||
outside_boundary_condition_object = f'Building_{building.name}_surface_{index}'
|
|
||||||
outside_boundary_condition = idf_cte.SURFACE
|
|
||||||
sun_exposure = idf_cte.NON_SUN_EXPOSED
|
|
||||||
wind_exposure = idf_cte.NON_WIND_EXPOSED
|
|
||||||
self._write_to_idf_format(file, idf_cte.BUILDING_SURFACE)
|
|
||||||
self._write_to_idf_format(file, name, 'Name')
|
|
||||||
self._write_to_idf_format(file, surface_type, 'Surface Type')
|
|
||||||
self._write_to_idf_format(file, construction_name, 'Construction Name')
|
|
||||||
self._write_to_idf_format(file, zone_name, 'Zone Name')
|
|
||||||
self._write_to_idf_format(file, space_name, 'Space Name')
|
|
||||||
self._write_to_idf_format(file, outside_boundary_condition, 'Outside Boundary Condition')
|
|
||||||
self._write_to_idf_format(file, outside_boundary_condition_object, 'Outside Boundary Condition Object')
|
|
||||||
self._write_to_idf_format(file, sun_exposure, 'Sun Exposure')
|
|
||||||
self._write_to_idf_format(file, wind_exposure, 'Wind Exposure')
|
|
||||||
self._write_to_idf_format(file, idf_cte.AUTOCALCULATE, 'View Factor to Ground')
|
|
||||||
self._write_to_idf_format(file, idf_cte.AUTOCALCULATE, 'Number of Vertices')
|
|
||||||
coordinates = self._matrix_to_list(boundary.parent_surface.solid_polygon.coordinates,
|
|
||||||
self._city.lower_corner)
|
|
||||||
eol = ','
|
|
||||||
coordinates_length = len(coordinates)
|
|
||||||
for i, coordinate in enumerate(coordinates):
|
|
||||||
vertex = i + 1
|
|
||||||
if vertex == coordinates_length:
|
|
||||||
eol = ';'
|
|
||||||
self._write_to_idf_format(file, coordinate[0], f'Vertex {vertex} Xcoordinate')
|
|
||||||
self._write_to_idf_format(file, coordinate[1], f'Vertex {vertex} Ycoordinate')
|
|
||||||
self._write_to_idf_format(file, coordinate[2], f'Vertex {vertex} Zcoordinate', eol)
|
|
@ -1,18 +0,0 @@
|
|||||||
import hub.exports.building_energy.idf_helper as idf_cte
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
|
|
||||||
|
|
||||||
|
|
||||||
class IdfThermostat(IdfBase):
|
|
||||||
@staticmethod
|
|
||||||
def add(self, thermal_zone):
|
|
||||||
thermostat_name = f'Thermostat {thermal_zone.usage_name}'
|
|
||||||
heating_schedule = f'Heating thermostat schedules {thermal_zone.usage_name}'
|
|
||||||
cooling_schedule = f'Cooling thermostat schedules {thermal_zone.usage_name}'
|
|
||||||
if thermostat_name not in self._thermostat_added_to_idf:
|
|
||||||
self._thermostat_added_to_idf[thermostat_name] = True
|
|
||||||
file = self._files['thermostat']
|
|
||||||
self._write_to_idf_format(file, idf_cte.THERMOSTAT)
|
|
||||||
self._write_to_idf_format(file, thermostat_name, 'Name')
|
|
||||||
self._write_to_idf_format(file, heating_schedule, 'Heating Setpoint Schedule Name')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Constant Heating Setpoint')
|
|
||||||
self._write_to_idf_format(file, cooling_schedule, 'Cooling Setpoint Schedule Name', ';')
|
|
@ -1,38 +0,0 @@
|
|||||||
import hub.exports.building_energy.idf_helper as idf_cte
|
|
||||||
import hub.helpers.constants as cte
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
|
|
||||||
|
|
||||||
|
|
||||||
class IdfVentilation(IdfBase):
|
|
||||||
@staticmethod
|
|
||||||
def add(self, thermal_zone, zone_name):
|
|
||||||
schedule_name = f'Ventilation schedules {thermal_zone.usage_name}'
|
|
||||||
air_change = thermal_zone.mechanical_air_change * cte.HOUR_TO_SECONDS
|
|
||||||
file = self._files['ventilation']
|
|
||||||
self._write_to_idf_format(file, idf_cte.VENTILATION)
|
|
||||||
self._write_to_idf_format(file, f'{zone_name}_ventilation', 'Name')
|
|
||||||
self._write_to_idf_format(file, zone_name, 'Zone or ZoneList or Space or SpaceList Name')
|
|
||||||
self._write_to_idf_format(file, schedule_name, 'Schedule Name')
|
|
||||||
self._write_to_idf_format(file, 'AirChanges/Hour', 'Design Flow Rate Calculation Method')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Design Flow Rate')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Flow Rate per Floor Area')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Flow Rate per Person')
|
|
||||||
self._write_to_idf_format(file, air_change, 'Air Changes per Hour')
|
|
||||||
self._write_to_idf_format(file, 'Natural', 'Ventilation Type')
|
|
||||||
self._write_to_idf_format(file, 0, 'Fan Pressure Rise')
|
|
||||||
self._write_to_idf_format(file, 1, 'Fan Total Efficiency')
|
|
||||||
self._write_to_idf_format(file, 1, 'Constant Term Coefficient')
|
|
||||||
self._write_to_idf_format(file, 0, 'Temperature Term Coefficient')
|
|
||||||
self._write_to_idf_format(file, 0, 'Velocity Term Coefficient')
|
|
||||||
self._write_to_idf_format(file, 0, 'Velocity Squared Term Coefficient')
|
|
||||||
self._write_to_idf_format(file, -100, 'Minimum Indoor Temperature')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Minimum Indoor Temperature Schedule Name')
|
|
||||||
self._write_to_idf_format(file, 100, 'Maximum Indoor Temperature')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Maximum Indoor Temperature Schedule Name')
|
|
||||||
self._write_to_idf_format(file, -100, 'Delta Temperature')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Delta Temperature Schedule Name')
|
|
||||||
self._write_to_idf_format(file, -100, 'Minimum Outdoor Temperature')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Minimum Outdoor Temperature Schedule Name')
|
|
||||||
self._write_to_idf_format(file, 100, 'Maximum Outdoor Temperature')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Maximum Outdoor Temperature Schedule Name')
|
|
||||||
self._write_to_idf_format(file, 40, 'Maximum Wind Speed', ';')
|
|
@ -1,64 +0,0 @@
|
|||||||
import logging
|
|
||||||
|
|
||||||
import hub.exports.building_energy.idf_helper as idf_cte
|
|
||||||
import hub.helpers.constants as cte
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
|
|
||||||
|
|
||||||
|
|
||||||
class IdfWindow(IdfBase):
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _to_window_surface(self, surface):
|
|
||||||
window_ratio = surface.associated_thermal_boundaries[0].window_ratio
|
|
||||||
x = 0
|
|
||||||
y = 1
|
|
||||||
z = 2
|
|
||||||
coordinates = self._matrix_to_list(surface.solid_polygon.coordinates, self._city.lower_corner)
|
|
||||||
min_z = surface.lower_corner[z]
|
|
||||||
max_z = surface.upper_corner[z]
|
|
||||||
middle = (max_z - min_z) / 2
|
|
||||||
distance = (max_z - min_z) * window_ratio
|
|
||||||
new_max_z = middle + distance / 2
|
|
||||||
new_min_z = middle - distance / 2
|
|
||||||
for index, coordinate in enumerate(coordinates):
|
|
||||||
if coordinate[z] == max_z:
|
|
||||||
coordinates[index] = (coordinate[x], coordinate[y], new_max_z)
|
|
||||||
elif coordinate[z] == min_z:
|
|
||||||
coordinates[index] = (coordinate[x], coordinate[y], new_min_z)
|
|
||||||
else:
|
|
||||||
logging.warning('Z coordinate not in top or bottom during window creation')
|
|
||||||
return coordinates
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def add(self, building):
|
|
||||||
file = self._files['fenestration']
|
|
||||||
for thermal_zone in building.thermal_zones_from_internal_zones:
|
|
||||||
for index, boundary in enumerate(thermal_zone.thermal_boundaries):
|
|
||||||
building_surface_name = f'Building_{building.name}_surface_{index}'
|
|
||||||
is_exposed = boundary.parent_surface.type == cte.WALL
|
|
||||||
if boundary.parent_surface.percentage_shared is not None and boundary.parent_surface.percentage_shared > 0.5 or boundary.window_ratio == 0:
|
|
||||||
is_exposed = False
|
|
||||||
if not is_exposed:
|
|
||||||
continue
|
|
||||||
name = f'Building_{building.name}_window_{index}'
|
|
||||||
construction_name = f'{boundary.construction_name}_window_construction'
|
|
||||||
self._write_to_idf_format(file, idf_cte.WINDOW_SURFACE)
|
|
||||||
self._write_to_idf_format(file, name, 'Name')
|
|
||||||
self._write_to_idf_format(file, 'Window', 'Surface Type')
|
|
||||||
self._write_to_idf_format(file, construction_name, 'Construction Name')
|
|
||||||
self._write_to_idf_format(file, building_surface_name, 'Building Surface Name')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Outside Boundary Condition Object')
|
|
||||||
self._write_to_idf_format(file, idf_cte.AUTOCALCULATE, 'View Factor to Ground')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Frame and Divider Name')
|
|
||||||
self._write_to_idf_format(file, '1.0', 'Multiplier')
|
|
||||||
self._write_to_idf_format(file, idf_cte.AUTOCALCULATE, 'Number of Vertices')
|
|
||||||
coordinates = IdfWindow._to_window_surface(self, boundary.parent_surface)
|
|
||||||
eol = ','
|
|
||||||
coordinates_length = len(coordinates)
|
|
||||||
for i, coordinate in enumerate(coordinates):
|
|
||||||
vertex = i + 1
|
|
||||||
if vertex == coordinates_length:
|
|
||||||
eol = ';'
|
|
||||||
self._write_to_idf_format(file, coordinate[0], f'Vertex {vertex} Xcoordinate')
|
|
||||||
self._write_to_idf_format(file, coordinate[1], f'Vertex {vertex} Ycoordinate')
|
|
||||||
self._write_to_idf_format(file, coordinate[2], f'Vertex {vertex} Zcoordinate', eol)
|
|
@ -1,17 +0,0 @@
|
|||||||
import hub.exports.building_energy.idf_helper as idf_cte
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
|
|
||||||
|
|
||||||
|
|
||||||
class IdfWindowsConstructions(IdfBase):
|
|
||||||
@staticmethod
|
|
||||||
def add(self, thermal_boundary):
|
|
||||||
name = f'{thermal_boundary.construction_name}_window'
|
|
||||||
if name not in self._windows_added_to_idf:
|
|
||||||
return # Material not added or already assigned to construction
|
|
||||||
construction_name = f'{thermal_boundary.construction_name}_window_construction'
|
|
||||||
if construction_name not in self._constructions_added_to_idf:
|
|
||||||
self._constructions_added_to_idf[construction_name] = True
|
|
||||||
file = self._files['constructions']
|
|
||||||
self._write_to_idf_format(file, idf_cte.CONSTRUCTION)
|
|
||||||
self._write_to_idf_format(file, construction_name, 'Name')
|
|
||||||
self._write_to_idf_format(file, name, 'Outside Layer', ';')
|
|
@ -1,15 +0,0 @@
|
|||||||
import hub.exports.building_energy.idf_helper as idf_cte
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
|
|
||||||
|
|
||||||
|
|
||||||
class IdfWindowsMaterial(IdfBase):
|
|
||||||
@staticmethod
|
|
||||||
def add(self, thermal_boundary, thermal_opening):
|
|
||||||
name = f'{thermal_boundary.construction_name}_window'
|
|
||||||
if name not in self._windows_added_to_idf:
|
|
||||||
self._windows_added_to_idf[name] = True
|
|
||||||
file = self._files['window_materials']
|
|
||||||
self._write_to_idf_format(file, idf_cte.WINDOW_MATERIAL)
|
|
||||||
self._write_to_idf_format(file, name, 'Name')
|
|
||||||
self._write_to_idf_format(file, thermal_opening.overall_u_value, 'UFactor')
|
|
||||||
self._write_to_idf_format(file, thermal_opening.g_value, 'Solar Heat Gain Coefficient', ';')
|
|
@ -1,22 +0,0 @@
|
|||||||
import hub.exports.building_energy.idf_helper as idf_cte
|
|
||||||
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
|
|
||||||
|
|
||||||
|
|
||||||
class IdfZone(IdfBase):
|
|
||||||
@staticmethod
|
|
||||||
def add(self, thermal_zone, zone_name):
|
|
||||||
file = self._files['zones']
|
|
||||||
self._write_to_idf_format(file, idf_cte.ZONE)
|
|
||||||
self._write_to_idf_format(file, zone_name, 'Name')
|
|
||||||
self._write_to_idf_format(file, 0, 'Direction of Relative North')
|
|
||||||
self._write_to_idf_format(file, 0, 'X Origin')
|
|
||||||
self._write_to_idf_format(file, 0, 'Y Origin')
|
|
||||||
self._write_to_idf_format(file, 0, 'Z Origin')
|
|
||||||
self._write_to_idf_format(file, 1, 'Type')
|
|
||||||
self._write_to_idf_format(file, 1, 'Multiplier')
|
|
||||||
self._write_to_idf_format(file, idf_cte.AUTOCALCULATE, 'Ceiling Height')
|
|
||||||
self._write_to_idf_format(file, thermal_zone.volume, 'Volume')
|
|
||||||
self._write_to_idf_format(file, idf_cte.AUTOCALCULATE, 'Floor Area')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Zone Inside Convection Algorithm')
|
|
||||||
self._write_to_idf_format(file, idf_cte.EMPTY, 'Zone Outside Convection Algorithm')
|
|
||||||
self._write_to_idf_format(file, 'Yes', 'Part of Total Floor Area', ';')
|
|
@ -11,7 +11,6 @@ import requests
|
|||||||
|
|
||||||
from hub.exports.building_energy.energy_ade import EnergyAde
|
from hub.exports.building_energy.energy_ade import EnergyAde
|
||||||
from hub.exports.building_energy.idf import Idf
|
from hub.exports.building_energy.idf import Idf
|
||||||
from hub.exports.building_energy.cerc_idf import CercIdf
|
|
||||||
from hub.exports.building_energy.insel.insel_monthly_energy_balance import InselMonthlyEnergyBalance
|
from hub.exports.building_energy.insel.insel_monthly_energy_balance import InselMonthlyEnergyBalance
|
||||||
from hub.helpers.utils import validate_import_export_type
|
from hub.helpers.utils import validate_import_export_type
|
||||||
from hub.imports.weather.helpers.weather import Weather as wh
|
from hub.imports.weather.helpers.weather import Weather as wh
|
||||||
@ -21,7 +20,6 @@ class EnergyBuildingsExportsFactory:
|
|||||||
"""
|
"""
|
||||||
Energy Buildings exports factory class
|
Energy Buildings exports factory class
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, handler, city, path, custom_insel_block='d18599', target_buildings=None, weather_file=None):
|
def __init__(self, handler, city, path, custom_insel_block='d18599', target_buildings=None, weather_file=None):
|
||||||
self._city = city
|
self._city = city
|
||||||
self._export_type = '_' + handler.lower()
|
self._export_type = '_' + handler.lower()
|
||||||
@ -64,17 +62,6 @@ class EnergyBuildingsExportsFactory:
|
|||||||
return Idf(self._city, self._path, (idf_data_path / 'Minimal.idf'), (idf_data_path / 'Energy+.idd'),
|
return Idf(self._city, self._path, (idf_data_path / 'Minimal.idf'), (idf_data_path / 'Energy+.idd'),
|
||||||
self._weather_file, target_buildings=self._target_buildings)
|
self._weather_file, target_buildings=self._target_buildings)
|
||||||
|
|
||||||
@property
|
|
||||||
def _cerc_idf(self):
|
|
||||||
idf_data_path = (Path(__file__).parent / './building_energy/idf_files/').resolve()
|
|
||||||
url = wh().epw_file(self._city.region_code)
|
|
||||||
weather_path = (Path(__file__).parent.parent / f'data/weather/epw/{url.rsplit("/", 1)[1]}').resolve()
|
|
||||||
if not weather_path.exists():
|
|
||||||
with open(weather_path, 'wb') as epw_file:
|
|
||||||
epw_file.write(requests.get(url, allow_redirects=True).content)
|
|
||||||
return CercIdf(self._city, self._path, (idf_data_path / 'base.idf'), (idf_data_path / 'Energy+.idd'), weather_path,
|
|
||||||
target_buildings=self._target_buildings)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _insel_monthly_energy_balance(self):
|
def _insel_monthly_energy_balance(self):
|
||||||
"""
|
"""
|
||||||
|
@ -77,8 +77,8 @@ class CesiumjsTileset:
|
|||||||
'function': {
|
'function': {
|
||||||
'type': 'STRING'
|
'type': 'STRING'
|
||||||
},
|
},
|
||||||
'usages': {
|
'usages_percentage': {
|
||||||
'type': 'LIST'
|
'type': 'STRING'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -146,7 +146,7 @@ class CesiumjsTileset:
|
|||||||
'max_height': building.max_height,
|
'max_height': building.max_height,
|
||||||
'year_of_construction': building.year_of_construction,
|
'year_of_construction': building.year_of_construction,
|
||||||
'function': building.function,
|
'function': building.function,
|
||||||
'usages': building.usages
|
'usages_percentage': building.usages
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'content': {
|
'content': {
|
||||||
|
@ -26,6 +26,7 @@ WATTS_HOUR_TO_JULES = 3600
|
|||||||
GALLONS_TO_QUBIC_METERS = 0.0037854117954011185
|
GALLONS_TO_QUBIC_METERS = 0.0037854117954011185
|
||||||
INFILTRATION_75PA_TO_4PA = (4/75)**0.65
|
INFILTRATION_75PA_TO_4PA = (4/75)**0.65
|
||||||
|
|
||||||
|
|
||||||
# time
|
# time
|
||||||
SECOND = 'second'
|
SECOND = 'second'
|
||||||
MINUTE = 'minute'
|
MINUTE = 'minute'
|
||||||
@ -185,19 +186,6 @@ DAYS_A_MONTH = {JANUARY: 31,
|
|||||||
NOVEMBER: 30,
|
NOVEMBER: 30,
|
||||||
DECEMBER: 31}
|
DECEMBER: 31}
|
||||||
|
|
||||||
HOURS_A_MONTH = {JANUARY: 744,
|
|
||||||
FEBRUARY: 672,
|
|
||||||
MARCH: 744,
|
|
||||||
APRIL: 720,
|
|
||||||
MAY: 744,
|
|
||||||
JUNE: 720,
|
|
||||||
JULY: 744,
|
|
||||||
AUGUST: 744,
|
|
||||||
SEPTEMBER: 720,
|
|
||||||
OCTOBER: 744,
|
|
||||||
NOVEMBER: 720,
|
|
||||||
DECEMBER: 744}
|
|
||||||
|
|
||||||
# data types
|
# data types
|
||||||
ANY_NUMBER = 'any_number'
|
ANY_NUMBER = 'any_number'
|
||||||
FRACTION = 'fraction'
|
FRACTION = 'fraction'
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
"""
|
"""
|
||||||
Cerc Idf result import
|
Insel monthly energy balance
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2022 Concordia CERC group
|
Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Guille Guillermo.GutierrezMorote@concordia.ca
|
Project Coder Saeed Ranjbar saeed.ranjbar@concordia.ca
|
||||||
Code contributors: Saeed Ranjbar saeed.ranjbar@concordia.ca
|
Project collaborator Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
from pathlib import Path
|
||||||
import csv
|
import csv
|
||||||
|
|
||||||
|
from hub.helpers.monthly_values import MonthlyValues
|
||||||
import hub.helpers.constants as cte
|
import hub.helpers.constants as cte
|
||||||
|
|
||||||
|
|
||||||
@ -14,33 +16,62 @@ class EnergyPlus:
|
|||||||
"""
|
"""
|
||||||
Energy plus class
|
Energy plus class
|
||||||
"""
|
"""
|
||||||
|
def __init__(self, city, base_path):
|
||||||
def _extract_fields_from_headers(self, headers):
|
|
||||||
for header in headers:
|
|
||||||
header_parts = header.split(':')
|
|
||||||
building_name = header_parts[0]
|
|
||||||
variable = ':'.join(header_parts[1:]).strip() # concat the rest and ensure that : it's reintroduced just in case
|
|
||||||
if variable == '':
|
|
||||||
continue
|
|
||||||
if building_name not in self._summary_variables:
|
|
||||||
self._building_energy_demands[variable] = [] # initialize the list of variables
|
|
||||||
else:
|
|
||||||
self._building_energy_demands[header] = []
|
|
||||||
|
|
||||||
def __init__(self, city, file_path):
|
|
||||||
self._city = city
|
self._city = city
|
||||||
self._building_energy_demands = {}
|
self._base_path = base_path
|
||||||
self._lines = []
|
|
||||||
self._summary_variables = ['DistrictCooling:Facility [J](Hourly)',
|
|
||||||
'InteriorEquipment:Electricity [J](Hourly)',
|
|
||||||
'InteriorLights:Electricity [J](Hourly) ']
|
|
||||||
|
|
||||||
with open(file_path, 'r', encoding='utf8') as csv_file:
|
@staticmethod
|
||||||
|
def _building_energy_demands(energy_plus_output_file_path):
|
||||||
|
with open(Path(energy_plus_output_file_path).resolve(), 'r', encoding='utf8') as csv_file:
|
||||||
csv_output = csv.reader(csv_file)
|
csv_output = csv.reader(csv_file)
|
||||||
self._headers = next(csv_output)
|
headers = next(csv_output)
|
||||||
self._extract_fields_from_headers(self._headers)
|
building_energy_demands = {
|
||||||
|
'Heating (J)': [],
|
||||||
|
'Cooling (J)': [],
|
||||||
|
'DHW (J)': [],
|
||||||
|
'Appliances (J)': [],
|
||||||
|
'Lighting (J)': []
|
||||||
|
}
|
||||||
|
heating_column_index = []
|
||||||
|
cooling_column_index = []
|
||||||
|
dhw_column_index = []
|
||||||
|
appliance_column_index = []
|
||||||
|
lighting_column_index = []
|
||||||
|
for index, header in enumerate(headers):
|
||||||
|
if "Total Heating" in header:
|
||||||
|
heating_column_index.append(index)
|
||||||
|
elif "Total Cooling" in header:
|
||||||
|
cooling_column_index.append(index)
|
||||||
|
elif "DHW" in header:
|
||||||
|
dhw_column_index.append(index)
|
||||||
|
elif "InteriorEquipment" in header:
|
||||||
|
appliance_column_index.append(index)
|
||||||
|
elif "InteriorLights" in header:
|
||||||
|
lighting_column_index.append(index)
|
||||||
|
|
||||||
for line in csv_output:
|
for line in csv_output:
|
||||||
self._lines.append(line)
|
total_heating_demand = 0
|
||||||
|
total_cooling_demand = 0
|
||||||
|
total_dhw_demand = 0
|
||||||
|
total_appliance_demand = 0
|
||||||
|
total_lighting_demand = 0
|
||||||
|
for heating_index in heating_column_index:
|
||||||
|
total_heating_demand += float(line[heating_index])
|
||||||
|
building_energy_demands['Heating (J)'].append(total_heating_demand)
|
||||||
|
for cooling_index in cooling_column_index:
|
||||||
|
total_cooling_demand += float(line[cooling_index])
|
||||||
|
building_energy_demands['Cooling (J)'].append(total_cooling_demand)
|
||||||
|
for dhw_index in dhw_column_index:
|
||||||
|
total_dhw_demand += float(line[dhw_index]) * 3600
|
||||||
|
building_energy_demands['DHW (J)'].append(total_dhw_demand)
|
||||||
|
for appliance_index in appliance_column_index:
|
||||||
|
total_appliance_demand += float(line[appliance_index])
|
||||||
|
building_energy_demands['Appliances (J)'].append(total_appliance_demand)
|
||||||
|
for lighting_index in lighting_column_index:
|
||||||
|
total_lighting_demand += float(line[lighting_index])
|
||||||
|
building_energy_demands['Lighting (J)'].append(total_lighting_demand)
|
||||||
|
|
||||||
|
return building_energy_demands
|
||||||
|
|
||||||
def enrich(self):
|
def enrich(self):
|
||||||
"""
|
"""
|
||||||
@ -48,58 +79,27 @@ class EnergyPlus:
|
|||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
for building in self._city.buildings:
|
for building in self._city.buildings:
|
||||||
_energy_demands = {}
|
file_name = f'{building.name}_out.csv'
|
||||||
for header in self._building_energy_demands:
|
energy_plus_output_file_path = Path(self._base_path / file_name).resolve()
|
||||||
print(header)
|
if energy_plus_output_file_path.is_file():
|
||||||
if header == 'Zone Ideal Loads Supply Air Total Heating Energy [J](Hourly)':
|
building_energy_demands = self._building_energy_demands(energy_plus_output_file_path)
|
||||||
field_name = f'{building.name} IDEAL LOADS AIR SYSTEM:{header}'
|
building.heating_demand[cte.HOUR] = building_energy_demands['Heating (J)']
|
||||||
elif header == 'Zone Ideal Loads Supply Air Total Cooling Energy [J](Hourly)':
|
building.cooling_demand[cte.HOUR] = building_energy_demands['Cooling (J)']
|
||||||
field_name = f'{building.name} IDEAL LOADS AIR SYSTEM:{header}'
|
building.domestic_hot_water_heat_demand[cte.HOUR] = building_energy_demands['DHW (J)']
|
||||||
else:
|
building.appliances_electrical_demand[cte.HOUR] = building_energy_demands['Appliances (J)']
|
||||||
field_name = f'{building.name}:{header}'
|
building.lighting_electrical_demand[cte.HOUR] = building_energy_demands['Lighting (J)']
|
||||||
position = -1
|
# todo: @Saeed, this a list of ONE value with the total energy of the year, exactly the same as cte.YEAR.
|
||||||
if field_name in self._headers:
|
# You have to use the method to add hourly values from helpers/monthly_values
|
||||||
position = self._headers.index(field_name)
|
building.heating_demand[cte.MONTH] = MonthlyValues.get_total_month(building.heating_demand[cte.HOUR])
|
||||||
if position == -1:
|
building.cooling_demand[cte.MONTH] = MonthlyValues.get_total_month(building.cooling_demand[cte.HOUR])
|
||||||
continue
|
building.domestic_hot_water_heat_demand[cte.MONTH] = (
|
||||||
for line in self._lines:
|
MonthlyValues.get_total_month(building.domestic_hot_water_heat_demand[cte.HOUR]))
|
||||||
if header not in _energy_demands.keys():
|
building.appliances_electrical_demand[cte.MONTH] = (
|
||||||
_energy_demands[header] = []
|
MonthlyValues.get_total_month(building.appliances_electrical_demand[cte.HOUR]))
|
||||||
_energy_demands[header].append(line[position])
|
building.lighting_electrical_demand[cte.MONTH] = (
|
||||||
# print(building_energy_demands['Zone Ideal Loads Supply Air Total Heating Energy [J](Hourly)'])
|
MonthlyValues.get_total_month(building.lighting_electrical_demand[cte.HOUR]))
|
||||||
EnergyPlus._set_building_demands(building, _energy_demands)
|
building.heating_demand[cte.YEAR] = [sum(building.heating_demand[cte.MONTH])]
|
||||||
|
building.cooling_demand[cte.YEAR] = [sum(building.cooling_demand[cte.MONTH])]
|
||||||
@staticmethod
|
building.domestic_hot_water_heat_demand[cte.YEAR] = [sum(building.domestic_hot_water_heat_demand[cte.MONTH])]
|
||||||
def _set_building_demands(building, energy_demands):
|
building.appliances_electrical_demand[cte.YEAR] = [sum(building.appliances_electrical_demand[cte.MONTH])]
|
||||||
print(energy_demands.keys())
|
building.lighting_electrical_demand[cte.YEAR] = [sum(building.lighting_electrical_demand[cte.MONTH])]
|
||||||
heating = [float(x) for x in energy_demands['Zone Ideal Loads Supply Air Total Heating Energy [J](Hourly)']]
|
|
||||||
cooling = [float(x) for x in energy_demands['Zone Ideal Loads Supply Air Total Cooling Energy [J](Hourly)']]
|
|
||||||
dhw = [float(x) * cte.WATTS_HOUR_TO_JULES for x in energy_demands['Water Use Equipment Heating Rate [W](Hourly)']]
|
|
||||||
appliances = [float(x) * cte.WATTS_HOUR_TO_JULES for x in energy_demands['Other Equipment Electricity Rate [W](Hourly)']]
|
|
||||||
lighting = [float(x) * cte.WATTS_HOUR_TO_JULES for x in energy_demands['Zone Lights Electricity Rate [W](Hourly)']]
|
|
||||||
building.heating_demand[cte.HOUR] = heating
|
|
||||||
building.cooling_demand[cte.HOUR] = cooling
|
|
||||||
building.domestic_hot_water_heat_demand[cte.HOUR] = dhw
|
|
||||||
building.appliances_electrical_demand[cte.HOUR] = appliances
|
|
||||||
building.lighting_electrical_demand[cte.HOUR] = lighting
|
|
||||||
building.heating_demand[cte.MONTH] = []
|
|
||||||
building.cooling_demand[cte.MONTH] = []
|
|
||||||
building.domestic_hot_water_heat_demand[cte.MONTH] = []
|
|
||||||
building.appliances_electrical_demand[cte.MONTH] = []
|
|
||||||
building.lighting_electrical_demand[cte.MONTH] = []
|
|
||||||
|
|
||||||
start = 0
|
|
||||||
|
|
||||||
for hours in cte.HOURS_A_MONTH.values():
|
|
||||||
end = hours + start
|
|
||||||
building.heating_demand[cte.MONTH].append(sum(building.heating_demand[cte.HOUR][start: end]))
|
|
||||||
building.cooling_demand[cte.MONTH].append(sum(building.cooling_demand[cte.HOUR][start: end]))
|
|
||||||
building.domestic_hot_water_heat_demand[cte.MONTH].append(sum(dhw[start: end]))
|
|
||||||
building.appliances_electrical_demand[cte.MONTH].append(sum(appliances[start: end]))
|
|
||||||
building.lighting_electrical_demand[cte.MONTH].append(sum(lighting[start: end]))
|
|
||||||
start = end
|
|
||||||
building.heating_demand[cte.YEAR] = [sum(building.heating_demand[cte.HOUR])]
|
|
||||||
building.cooling_demand[cte.YEAR] = [sum(building.cooling_demand[cte.HOUR])]
|
|
||||||
building.domestic_hot_water_heat_demand[cte.YEAR] = [sum(building.domestic_hot_water_heat_demand[cte.HOUR])]
|
|
||||||
building.appliances_electrical_demand[cte.YEAR] = [sum(building.appliances_electrical_demand[cte.HOUR])]
|
|
||||||
building.lighting_electrical_demand[cte.YEAR] = [sum(building.lighting_electrical_demand[cte.HOUR])]
|
|
||||||
|
@ -22,11 +22,9 @@ class EnergyPlusMultipleBuildings:
|
|||||||
|
|
||||||
with open(Path(energy_plus_output_file_path).resolve(), 'r', encoding='utf8') as csv_file:
|
with open(Path(energy_plus_output_file_path).resolve(), 'r', encoding='utf8') as csv_file:
|
||||||
csv_output = list(csv.DictReader(csv_file))
|
csv_output = list(csv.DictReader(csv_file))
|
||||||
print(csv_output)
|
|
||||||
return
|
|
||||||
for building in self._city.buildings:
|
for building in self._city.buildings:
|
||||||
building_name = building.name.upper()
|
building_name = building.name.upper()
|
||||||
|
|
||||||
buildings_energy_demands[f'Building {building_name} Heating Demand (J)'] = [
|
buildings_energy_demands[f'Building {building_name} Heating Demand (J)'] = [
|
||||||
float(
|
float(
|
||||||
row[f"{building_name} IDEAL LOADS AIR SYSTEM:Zone Ideal Loads Supply Air Total Heating Energy [J](Hourly)"])
|
row[f"{building_name} IDEAL LOADS AIR SYSTEM:Zone Ideal Loads Supply Air Total Heating Energy [J](Hourly)"])
|
||||||
|
@ -8,7 +8,6 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from hub.helpers.utils import validate_import_export_type
|
from hub.helpers.utils import validate_import_export_type
|
||||||
from hub.imports.results.energy_plus import EnergyPlus
|
|
||||||
from hub.imports.results.insel_monthly_energry_balance import InselMonthlyEnergyBalance
|
from hub.imports.results.insel_monthly_energry_balance import InselMonthlyEnergyBalance
|
||||||
from hub.imports.results.simplified_radiosity_algorithm import SimplifiedRadiosityAlgorithm
|
from hub.imports.results.simplified_radiosity_algorithm import SimplifiedRadiosityAlgorithm
|
||||||
|
|
||||||
@ -61,9 +60,6 @@ class ResultFactory:
|
|||||||
"""
|
"""
|
||||||
EnergyPlusMultipleBuildings(self._city, self._base_path).enrich()
|
EnergyPlusMultipleBuildings(self._city, self._base_path).enrich()
|
||||||
|
|
||||||
def _cerc_idf(self):
|
|
||||||
EnergyPlus(self._city, self._base_path).enrich()
|
|
||||||
|
|
||||||
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
|
||||||
|
0
hub/imports/weather/EPWCLEANER
Normal file
0
hub/imports/weather/EPWCLEANER
Normal file
@ -9,7 +9,6 @@ import datetime
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from sqlalchemy import Column, Integer, String, Sequence, ForeignKey, Float
|
from sqlalchemy import Column, Integer, String, Sequence, ForeignKey, Float
|
||||||
from sqlalchemy.dialects.postgresql import JSON
|
|
||||||
from sqlalchemy import DateTime
|
from sqlalchemy import DateTime
|
||||||
|
|
||||||
from hub.city_model_structure.building import Building
|
from hub.city_model_structure.building import Building
|
||||||
@ -28,7 +27,7 @@ class CityObject(Models):
|
|||||||
type = Column(String, nullable=False)
|
type = Column(String, nullable=False)
|
||||||
year_of_construction = Column(Integer, nullable=True)
|
year_of_construction = Column(Integer, nullable=True)
|
||||||
function = Column(String, nullable=True)
|
function = Column(String, nullable=True)
|
||||||
usage = Column(JSON, nullable=True)
|
usage = Column(String, nullable=True)
|
||||||
volume = Column(Float, nullable=False)
|
volume = Column(Float, nullable=False)
|
||||||
area = Column(Float, nullable=False)
|
area = Column(Float, nullable=False)
|
||||||
total_heating_area = Column(Float, nullable=False)
|
total_heating_area = Column(Float, nullable=False)
|
||||||
@ -47,7 +46,7 @@ class CityObject(Models):
|
|||||||
self.type = building.type
|
self.type = building.type
|
||||||
self.year_of_construction = building.year_of_construction
|
self.year_of_construction = building.year_of_construction
|
||||||
self.function = building.function
|
self.function = building.function
|
||||||
self.usage = building.usages
|
self.usage = building.usages_percentage
|
||||||
self.volume = building.volume
|
self.volume = building.volume
|
||||||
self.area = building.floor_area
|
self.area = building.floor_area
|
||||||
self.roof_area = sum(roof.solid_polygon.area for roof in building.roofs)
|
self.roof_area = sum(roof.solid_polygon.area for roof in building.roofs)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
"""
|
"""
|
||||||
Hub version number
|
Hub version number
|
||||||
"""
|
"""
|
||||||
__version__ = '0.3.0.5'
|
__version__ = '0.2.0.19'
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
xmltodict
|
xmltodict
|
||||||
numpy
|
numpy==1.26.4
|
||||||
trimesh[all]
|
trimesh[all]
|
||||||
pyproj
|
pyproj
|
||||||
pandas
|
pandas
|
||||||
|
1
setup.py
1
setup.py
@ -59,7 +59,6 @@ setup(
|
|||||||
'hub.exports',
|
'hub.exports',
|
||||||
'hub.exports.building_energy',
|
'hub.exports.building_energy',
|
||||||
'hub.exports.building_energy.idf_files',
|
'hub.exports.building_energy.idf_files',
|
||||||
'hub.exports.building_energy.idf_helper',
|
|
||||||
'hub.exports.building_energy.insel',
|
'hub.exports.building_energy.insel',
|
||||||
'hub.exports.energy_systems',
|
'hub.exports.energy_systems',
|
||||||
'hub.exports.formats',
|
'hub.exports.formats',
|
||||||
|
@ -17,7 +17,6 @@ from hub.exports.exports_factory import ExportsFactory
|
|||||||
from hub.helpers.dictionaries import Dictionaries
|
from hub.helpers.dictionaries import Dictionaries
|
||||||
from hub.imports.construction_factory import ConstructionFactory
|
from hub.imports.construction_factory import ConstructionFactory
|
||||||
from hub.imports.geometry_factory import GeometryFactory
|
from hub.imports.geometry_factory import GeometryFactory
|
||||||
from hub.imports.results_factory import ResultFactory
|
|
||||||
from hub.imports.usage_factory import UsageFactory
|
from hub.imports.usage_factory import UsageFactory
|
||||||
from hub.imports.weather_factory import WeatherFactory
|
from hub.imports.weather_factory import WeatherFactory
|
||||||
|
|
||||||
@ -137,49 +136,14 @@ class TestExports(TestCase):
|
|||||||
year_of_construction_field='ANNEE_CONS',
|
year_of_construction_field='ANNEE_CONS',
|
||||||
function_field='CODE_UTILI',
|
function_field='CODE_UTILI',
|
||||||
function_to_hub=Dictionaries().montreal_function_to_hub_function).city
|
function_to_hub=Dictionaries().montreal_function_to_hub_function).city
|
||||||
self.assertIsNotNone(city, 'city is none')
|
|
||||||
EnergyBuildingsExportsFactory('idf', city, self._output_path).export()
|
|
||||||
ConstructionFactory('nrcan', city).enrich()
|
|
||||||
EnergyBuildingsExportsFactory('idf', city, self._output_path).export()
|
|
||||||
UsageFactory('nrcan', city).enrich()
|
|
||||||
WeatherFactory('epw', city).enrich()
|
|
||||||
try:
|
|
||||||
_idf = EnergyBuildingsExportsFactory('idf', city, self._output_path).export()
|
|
||||||
_idf.run()
|
|
||||||
except Exception:
|
|
||||||
self.fail("Idf ExportsFactory raised ExceptionType unexpectedly!")
|
|
||||||
|
|
||||||
def test_cerc_idf_export(self):
|
|
||||||
"""
|
|
||||||
export to IDF
|
|
||||||
"""
|
|
||||||
file = 'test.geojson'
|
|
||||||
file_path = (self._example_path / file).resolve()
|
|
||||||
city = GeometryFactory('geojson',
|
|
||||||
path=file_path,
|
|
||||||
height_field='citygml_me',
|
|
||||||
year_of_construction_field='ANNEE_CONS',
|
|
||||||
function_field='CODE_UTILI',
|
|
||||||
function_to_hub=Dictionaries().montreal_function_to_hub_function).city
|
|
||||||
self.assertIsNotNone(city, 'city is none')
|
self.assertIsNotNone(city, 'city is none')
|
||||||
|
EnergyBuildingsExportsFactory('idf', city, self._output_path).export()
|
||||||
ConstructionFactory('nrcan', city).enrich()
|
ConstructionFactory('nrcan', city).enrich()
|
||||||
|
EnergyBuildingsExportsFactory('idf', city, self._output_path).export()
|
||||||
UsageFactory('nrcan', city).enrich()
|
UsageFactory('nrcan', city).enrich()
|
||||||
WeatherFactory('epw', city).enrich()
|
WeatherFactory('epw', city).enrich()
|
||||||
try:
|
try:
|
||||||
idf = EnergyBuildingsExportsFactory('cerc_idf', city, self._output_path).export()
|
EnergyBuildingsExportsFactory('idf', city, self._output_path, target_buildings=[1]).export()
|
||||||
idf.run()
|
|
||||||
csv_output_path = (self._output_path / f'{city.name}_out.csv').resolve()
|
|
||||||
ResultFactory('cerc_idf', city, csv_output_path).enrich()
|
|
||||||
self.assertTrue(csv_output_path.is_file())
|
|
||||||
for building in city.buildings:
|
|
||||||
self.assertIsNotNone(building.heating_demand)
|
|
||||||
self.assertIsNotNone(building.cooling_demand)
|
|
||||||
self.assertIsNotNone(building.domestic_hot_water_heat_demand)
|
|
||||||
self.assertIsNotNone(building.lighting_electrical_demand)
|
|
||||||
self.assertIsNotNone(building.appliances_electrical_demand)
|
|
||||||
total_demand = sum(building.heating_demand[cte.HOUR])
|
|
||||||
total_demand_month = sum(building.heating_demand[cte.MONTH])
|
|
||||||
self.assertAlmostEqual(total_demand, building.heating_demand[cte.YEAR][0], 2)
|
|
||||||
self.assertAlmostEqual(total_demand_month, building.heating_demand[cte.YEAR][0], 2)
|
|
||||||
except Exception:
|
except Exception:
|
||||||
self.fail("Idf ExportsFactory raised ExceptionType unexpectedly!")
|
self.fail("Idf ExportsFactory raised ExceptionType unexpectedly!")
|
||||||
|
@ -92,3 +92,42 @@ class TestResultsImport(TestCase):
|
|||||||
building.cooling_demand[cte.HOUR] = values
|
building.cooling_demand[cte.HOUR] = values
|
||||||
self.assertIsNotNone(building.heating_peak_load)
|
self.assertIsNotNone(building.heating_peak_load)
|
||||||
self.assertIsNotNone(building.cooling_peak_load)
|
self.assertIsNotNone(building.cooling_peak_load)
|
||||||
|
|
||||||
|
def test_energy_plus_results_import(self):
|
||||||
|
ResultFactory('energy_plus_single_building', self._city, self._example_path).enrich()
|
||||||
|
for building in self._city.buildings:
|
||||||
|
csv_output_name = f'{building.name}_out.csv'
|
||||||
|
csv_output_path = (self._example_path / csv_output_name).resolve()
|
||||||
|
if csv_output_path.is_file():
|
||||||
|
self.assertEqual(building.name, '12')
|
||||||
|
self.assertIsNotNone(building.heating_demand)
|
||||||
|
self.assertIsNotNone(building.cooling_demand)
|
||||||
|
self.assertIsNotNone(building.domestic_hot_water_heat_demand)
|
||||||
|
self.assertIsNotNone(building.lighting_electrical_demand)
|
||||||
|
self.assertIsNotNone(building.appliances_electrical_demand)
|
||||||
|
total_demand = sum(building.heating_demand[cte.HOUR])
|
||||||
|
self.assertAlmostEqual(total_demand, building.heating_demand[cte.YEAR][0], 3)
|
||||||
|
total_demand = sum(building.heating_demand[cte.MONTH])
|
||||||
|
self.assertEqual(total_demand, building.heating_demand[cte.YEAR][0], 3)
|
||||||
|
if building.name != '12':
|
||||||
|
self.assertDictEqual(building.heating_demand, {})
|
||||||
|
self.assertDictEqual(building.cooling_demand, {})
|
||||||
|
self.assertDictEqual(building.domestic_hot_water_heat_demand, {})
|
||||||
|
self.assertDictEqual(building.lighting_electrical_demand, {})
|
||||||
|
self.assertDictEqual(building.appliances_electrical_demand, {})
|
||||||
|
|
||||||
|
def test_energy_plus_multiple_buildings_results_import(self):
|
||||||
|
ResultFactory('energy_plus_multiple_buildings', self._city, self._example_path).enrich()
|
||||||
|
csv_output_name = f'{self._city.name}_out.csv'
|
||||||
|
csv_output_path = (self._example_path / csv_output_name).resolve()
|
||||||
|
if csv_output_path.is_file():
|
||||||
|
for building in self._city.buildings:
|
||||||
|
self.assertIsNotNone(building.heating_demand)
|
||||||
|
self.assertIsNotNone(building.cooling_demand)
|
||||||
|
self.assertIsNotNone(building.domestic_hot_water_heat_demand)
|
||||||
|
self.assertIsNotNone(building.lighting_electrical_demand)
|
||||||
|
self.assertIsNotNone(building.appliances_electrical_demand)
|
||||||
|
total_demand = sum(building.heating_demand[cte.HOUR])
|
||||||
|
self.assertAlmostEqual(total_demand, building.heating_demand[cte.YEAR][0], 2)
|
||||||
|
total_demand = sum(building.heating_demand[cte.MONTH])
|
||||||
|
self.assertEqual(total_demand, building.heating_demand[cte.YEAR][0], 2)
|
||||||
|
Loading…
Reference in New Issue
Block a user