cerc idf implementation

This commit is contained in:
Guille Gutierrez 2024-09-16 17:34:43 +02:00
parent cc2ee61ada
commit 62c9a5aab7
3 changed files with 96 additions and 16 deletions

View File

@ -25,7 +25,7 @@ class CercIdf:
_windows_added_to_idf = {'glazing_index': 0} _windows_added_to_idf = {'glazing_index': 0}
_constructions_added_to_idf = {} _constructions_added_to_idf = {}
def __init__(self, city, output_path, idf_file_path, idd_file_path, epw_file_path, export_type="Surfaces", def __init__(self, city, output_path, idf_file_path, idd_file_path, epw_file_path,
target_buildings=None): target_buildings=None):
self._city = city self._city = city
self._output_path = str(output_path.resolve()) self._output_path = str(output_path.resolve())
@ -41,9 +41,10 @@ class CercIdf:
self._output_lighting_path = str((output_path / 'lights.idf').resolve()) self._output_lighting_path = str((output_path / 'lights.idf').resolve())
self._output_appliances_path = str((output_path / 'appliances.idf').resolve()) self._output_appliances_path = str((output_path / 'appliances.idf').resolve())
self._output_surfaces_path = str((output_path / 'surfaces.idf').resolve()) self._output_surfaces_path = str((output_path / 'surfaces.idf').resolve())
self._output_infiltration_path = str((output_path / 'infiltration.idf').resolve())
self._output_ventilation_path = str((output_path / 'ventilation.idf').resolve())
self._output_file_path = str((output_path / f'{city.name}.idf').resolve()) self._output_file_path = str((output_path / f'{city.name}.idf').resolve())
self._export_type = export_type
self._idd_file_path = str(idd_file_path) self._idd_file_path = str(idd_file_path)
self._idf_file_path = str(idf_file_path) self._idf_file_path = str(idf_file_path)
self._epw_file_path = str(epw_file_path) self._epw_file_path = str(epw_file_path)
@ -71,7 +72,12 @@ class CercIdf:
self._output_lighting = open(self._output_lighting_path, 'w') self._output_lighting = open(self._output_lighting_path, 'w')
self._output_appliances = open(self._output_appliances_path, 'w') self._output_appliances = open(self._output_appliances_path, 'w')
self._output_surfaces = open(self._output_surfaces_path, 'w') self._output_surfaces = open(self._output_surfaces_path, 'w')
self._output_infiltration = open(self._output_infiltration_path, 'w')
self._output_ventilation = open(self._output_ventilation_path, 'w')
# Create base values
self._create_geometry_rules() self._create_geometry_rules()
with open(self._output_file_path, 'w') as self._idf_file: with open(self._output_file_path, 'w') as self._idf_file:
self._idf_file.writelines(lines) self._idf_file.writelines(lines)
self._export() self._export()
@ -88,20 +94,21 @@ class CercIdf:
self._output_lighting.close() self._output_lighting.close()
self._output_appliances.close() self._output_appliances.close()
self._output_surfaces.close() self._output_surfaces.close()
self._output_infiltration.close()
self._output_ventilation.close()
def _create_geometry_rules(self): def _create_geometry_rules(self):
"""
GlobalGeometryRules,
UpperLeftCorner, !- Starting Vertex Position
CounterClockWise, !- Vertex Entry Direction
World; !- Coordinate System
"""
file = self._output_zones file = self._output_zones
self._write_to_idf_format(file, idf_cte.GLOBAL_GEOMETRY_RULES) 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, 'UpperLeftCorner', 'Starting Vertex Position')
self._write_to_idf_format(file, 'CounterClockWise', 'Vertex Entry Direction') self._write_to_idf_format(file, 'CounterClockWise', 'Vertex Entry Direction')
self._write_to_idf_format(file, 'World', 'Coordinate System', ';') self._write_to_idf_format(file, 'World', 'Coordinate System', ';')
def _create_output_control_lighting(self):
file = self._output_appliances
self._write_to_idf_format(file, idf_cte.OUTPUT_CONTROL)
self._write_to_idf_format(file, 'Comma', 'Column Separator', ';')
@staticmethod @staticmethod
def _write_to_idf_format(file, field, comment='', eol=','): def _write_to_idf_format(file, field, comment='', eol=','):
if comment != '': if comment != '':
@ -235,7 +242,8 @@ class CercIdf:
for schedule in schedules: for schedule in schedules:
if schedule_name not in self._schedules_added_to_idf: if schedule_name not in self._schedules_added_to_idf:
self._schedules_added_to_idf[schedule_name] = True self._schedules_added_to_idf[schedule_name] = True
file_name = str((Path(self._output_path) / f'{schedule_type} schedules {usage.replace("/", "_")}.csv').resolve()) file_name = str(
(Path(self._output_path) / f'{schedule_type} schedules {usage.replace("/", "_")}.csv').resolve())
with open(file_name, 'w', encoding='utf8') as file: with open(file_name, 'w', encoding='utf8') as file:
for value in schedule.values: for value in schedule.values:
file.write(f'{str(value)},\n') file.write(f'{str(value)},\n')
@ -437,11 +445,12 @@ class CercIdf:
storeys_number = int(thermal_zone.total_floor_area / thermal_zone.footprint_area) storeys_number = int(thermal_zone.total_floor_area / thermal_zone.footprint_area)
watts_per_zone_floor_area = thermal_zone.lighting.density * storeys_number watts_per_zone_floor_area = thermal_zone.lighting.density * storeys_number
subcategory = f'ELECTRIC EQUIPMENT#{zone_name}#GeneralLights' subcategory = f'ELECTRIC EQUIPMENT#{zone_name}#GeneralLights'
schedule_name = f'Lighting schedules {thermal_zone.usage_name}'
file = self._output_lighting file = self._output_lighting
self._write_to_idf_format(file, idf_cte.LIGHTS) 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, 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, zone_name, 'Zone or ZoneList or Space or SpaceList Name')
self._write_to_idf_format(file, f'Lighting schedules {thermal_zone.usage_name}', 'Schedule 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, 'Watts/Area', 'Design Level Calculation Method')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Lighting Level') 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, watts_per_zone_floor_area, 'Watts per Zone Floor Area')
@ -453,7 +462,7 @@ class CercIdf:
self._write_to_idf_format(file, subcategory, 'EndUse Subcategory') 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, '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 1')
self._write_to_idf_format(file, 0, 'Return Air Fraction Function of Plenum Temperature Coefficient 2',';') self._write_to_idf_format(file, 0, 'Return Air Fraction Function of Plenum Temperature Coefficient 2', ';')
def _add_appliances(self, thermal_zone, zone_name): def _add_appliances(self, thermal_zone, zone_name):
schedule_name = f'Appliance schedules {thermal_zone.usage_name}' schedule_name = f'Appliance schedules {thermal_zone.usage_name}'
@ -476,6 +485,57 @@ class CercIdf:
self._write_to_idf_format(file, 0, 'Carbon Dioxide Generation Rate') self._write_to_idf_format(file, 0, 'Carbon Dioxide Generation Rate')
self._write_to_idf_format(file, subcategory, 'EndUse Subcategory', ';') self._write_to_idf_format(file, subcategory, 'EndUse Subcategory', ';')
def _add_infiltration(self, thermal_zone, zone_name):
schedule_name = f'Infiltration schedules {thermal_zone.usage_name}'
infiltration = thermal_zone.infiltration_rate_system_off * cte.HOUR_TO_SECONDS
file = self._output_infiltration
self._write_to_idf_format(file, idf_cte.INFILTRATION)
self._write_to_idf_format(file, f'{zone_name}_infiltration', '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 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', ';')
def _add_ventilation(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
infiltration = thermal_zone.infiltration_rate_system_off * cte.HOUR_TO_SECONDS
file = self._output_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', ';')
def _merge_files(self): def _merge_files(self):
self._output_schedules.flush() self._output_schedules.flush()
with open(self._output_schedules_path, 'r') as file: with open(self._output_schedules_path, 'r') as file:
@ -517,6 +577,15 @@ class CercIdf:
with open(self._output_appliances_path, 'r') as file: with open(self._output_appliances_path, 'r') as file:
lines = file.readlines() lines = file.readlines()
self._idf_file.writelines(lines) self._idf_file.writelines(lines)
# todo: this should be move down instead it's here to simplify validation
self._output_infiltration.flush()
with open(self._output_infiltration_path, 'r') as file:
lines = file.readlines()
self._idf_file.writelines(lines)
self._output_ventilation.flush()
with open(self._output_ventilation_path, 'r') as file:
lines = file.readlines()
self._idf_file.writelines(lines)
self._output_surfaces.flush() self._output_surfaces.flush()
with open(self._output_surfaces_path, 'r') as file: with open(self._output_surfaces_path, 'r') as file:
lines = file.readlines() lines = file.readlines()
@ -548,14 +617,18 @@ class CercIdf:
self._add_idf_schedules(usage, 'Ventilation', self._create_ventilation_schedules(thermal_zone)) self._add_idf_schedules(usage, 'Ventilation', self._create_ventilation_schedules(thermal_zone))
self._add_idf_schedules(usage, 'Occupancy', thermal_zone.occupancy.occupancy_schedules) self._add_idf_schedules(usage, 'Occupancy', thermal_zone.occupancy.occupancy_schedules)
self._add_idf_schedules(usage, 'HVAC AVAIL', thermal_zone.thermal_control.hvac_availability_schedules) self._add_idf_schedules(usage, 'HVAC AVAIL', thermal_zone.thermal_control.hvac_availability_schedules)
self._add_idf_schedules(usage, 'Heating thermostat', thermal_zone.thermal_control.heating_set_point_schedules) self._add_idf_schedules(usage, 'Heating thermostat',
self._add_idf_schedules(usage, 'Cooling thermostat', thermal_zone.thermal_control.cooling_set_point_schedules) thermal_zone.thermal_control.heating_set_point_schedules)
self._add_idf_schedules(usage, 'Cooling thermostat',
thermal_zone.thermal_control.cooling_set_point_schedules)
self._add_idf_schedules(usage, 'Lighting', thermal_zone.lighting.schedules) self._add_idf_schedules(usage, 'Lighting', thermal_zone.lighting.schedules)
self._add_idf_schedules(usage, 'Appliance', thermal_zone.appliances.schedules) self._add_idf_schedules(usage, 'Appliance', thermal_zone.appliances.schedules)
self._add_idf_schedules(usage, 'DHW_prof', thermal_zone.domestic_hot_water.schedules) self._add_idf_schedules(usage, 'DHW_prof', thermal_zone.domestic_hot_water.schedules)
self._add_idf_schedules(usage, 'DHW_temp', self._create_constant_value_schedules(service_temperature, 24)) self._add_idf_schedules(usage, 'DHW_temp', self._create_constant_value_schedules(service_temperature, 24))
self._add_idf_schedules(usage, 'Activity Level', self._create_constant_value_schedules(total_heat, 24)) self._add_idf_schedules(usage, 'Activity Level', self._create_constant_value_schedules(total_heat, 24))
self._add_file_schedules(usage, 'cold_temp', self._create_constant_value_schedules(building.cold_water_temperature[cte.HOUR], 24)) self._add_file_schedules(usage, 'cold_temp',
self._create_constant_value_schedules(building.cold_water_temperature[cte.HOUR],
24))
for thermal_boundary in thermal_zone.thermal_boundaries: for thermal_boundary in thermal_zone.thermal_boundaries:
self._add_materials(thermal_boundary) self._add_materials(thermal_boundary)
self._add_constructions(thermal_boundary) self._add_constructions(thermal_boundary)
@ -566,8 +639,11 @@ class CercIdf:
self._add_occupancy(thermal_zone, building.name) self._add_occupancy(thermal_zone, building.name)
self._add_lighting(thermal_zone, building.name) self._add_lighting(thermal_zone, building.name)
self._add_appliances(thermal_zone, building.name) self._add_appliances(thermal_zone, building.name)
self._add_infiltration(thermal_zone, building.name)
self._add_ventilation(thermal_zone, building.name)
if is_target: if is_target:
self._add_surfaces(building, building.name) self._add_surfaces(building, building.name)
self._create_output_control_lighting() # Add lighting control to the lighting
# Merge files # Merge files
self._merge_files() self._merge_files()

View File

@ -12,6 +12,10 @@ GLOBAL_GEOMETRY_RULES = '\nGlobalGeometryRules,\n'
PEOPLE = '\nPEOPLE,\n' PEOPLE = '\nPEOPLE,\n'
LIGHTS = '\nLIGHTS,\n' LIGHTS = '\nLIGHTS,\n'
APPLIANCES = '\nOTHEREQUIPMENT,\n' APPLIANCES = '\nOTHEREQUIPMENT,\n'
OUTPUT_CONTROL = '\nOutputControl:IlluminanceMap:Style,\n'
INFILTRATION = '\nZONEINFILTRATION:DESIGNFLOWRATE,\n'
VENTILATION = '\nZONEVENTILATION:DESIGNFLOWRATE,\n'
AUTOCALCULATE = 'autocalculate' AUTOCALCULATE = 'autocalculate'
ROUGHNESS = 'MediumRough' ROUGHNESS = 'MediumRough'

View File

@ -138,9 +138,9 @@ class TestExports(TestCase):
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') self.assertIsNotNone(city, 'city is none')
EnergyBuildingsExportsFactory('idf', city, self._output_path).export() #EnergyBuildingsExportsFactory('idf', city, self._output_path).export()
ConstructionFactory('nrcan', city).enrich() ConstructionFactory('nrcan', city).enrich()
EnergyBuildingsExportsFactory('idf', city, self._output_path).export() # 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: