cerc idf implementation refactoring and added systems
This commit is contained in:
parent
62c9a5aab7
commit
5e384c8185
|
@ -24,26 +24,34 @@ class CercIdf:
|
|||
_materials_added_to_idf = {}
|
||||
_windows_added_to_idf = {'glazing_index': 0}
|
||||
_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):
|
||||
self._city = city
|
||||
self._output_path = str(output_path.resolve())
|
||||
self._output_file_path = str((output_path / f'{city.name}.idf').resolve())
|
||||
self._output_schedules_path = str((output_path / 'schedules.idf').resolve())
|
||||
self._output_file_schedules_path = str((output_path / 'file_schedules.idf').resolve())
|
||||
self._output_solid_materials_path = str((output_path / 'solid_materials.idf').resolve())
|
||||
self._output_nomass_materials_path = str((output_path / 'nomass_materials.idf').resolve())
|
||||
self._output_window_materials_path = str((output_path / 'window_materials.idf').resolve())
|
||||
self._output_constructions_path = str((output_path / 'constructions.idf').resolve())
|
||||
self._output_zones_path = str((output_path / 'zones.idf').resolve())
|
||||
self._output_occupancy_path = str((output_path / 'occupancy.idf').resolve())
|
||||
self._output_lighting_path = str((output_path / 'lights.idf').resolve())
|
||||
self._output_appliances_path = str((output_path / 'appliances.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._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()),
|
||||
'occupancy': str((output_path / 'occupancy.idf').resolve()),
|
||||
'lighting': str((output_path / 'lights.idf').resolve()),
|
||||
'appliances': str((output_path / 'appliances.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()),
|
||||
'surfaces': str((output_path / 'surfaces.idf').resolve()) # todo: move surface to the right position after appliances
|
||||
}
|
||||
self._files = {}
|
||||
for key, value in self._file_paths.items():
|
||||
self._files[key] = open(value, 'w')
|
||||
|
||||
self._idd_file_path = str(idd_file_path)
|
||||
self._idf_file_path = str(idf_file_path)
|
||||
|
@ -61,20 +69,6 @@ class CercIdf:
|
|||
with open(self._idf_file_path, 'r') as base_idf:
|
||||
lines = base_idf.readlines()
|
||||
|
||||
self._output_schedules = open(self._output_schedules_path, 'w')
|
||||
self._output_file_schedules = open(self._output_file_schedules_path, 'w')
|
||||
self._output_solid_materials = open(self._output_solid_materials_path, 'w')
|
||||
self._output_nomass_materials = open(self._output_nomass_materials_path, 'w')
|
||||
self._output_window_materials = open(self._output_window_materials_path, 'w')
|
||||
self._output_constructions = open(self._output_constructions_path, 'w')
|
||||
self._output_zones = open(self._output_zones_path, 'w')
|
||||
self._output_occupancy = open(self._output_occupancy_path, 'w')
|
||||
self._output_lighting = open(self._output_lighting_path, 'w')
|
||||
self._output_appliances = open(self._output_appliances_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()
|
||||
|
||||
|
@ -82,30 +76,23 @@ class CercIdf:
|
|||
self._idf_file.writelines(lines)
|
||||
self._export()
|
||||
|
||||
def __del__(self):
|
||||
self._output_schedules.close()
|
||||
self._output_file_schedules.close()
|
||||
self._output_solid_materials.close()
|
||||
self._output_nomass_materials.close()
|
||||
self._output_window_materials.close()
|
||||
self._output_constructions.close()
|
||||
self._output_zones.close()
|
||||
self._output_occupancy.close()
|
||||
self._output_lighting.close()
|
||||
self._output_appliances.close()
|
||||
self._output_surfaces.close()
|
||||
self._output_infiltration.close()
|
||||
self._output_ventilation.close()
|
||||
def _merge_files(self):
|
||||
for file in self._files.values():
|
||||
file.close()
|
||||
for path in self._file_paths.values():
|
||||
with open(path, 'r') as file:
|
||||
lines = file.readlines()
|
||||
self._idf_file.writelines(lines)
|
||||
|
||||
def _create_geometry_rules(self):
|
||||
file = self._output_zones
|
||||
file = self._files['zones']
|
||||
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 _create_output_control_lighting(self):
|
||||
file = self._output_appliances
|
||||
file = self._files['appliances']
|
||||
self._write_to_idf_format(file, idf_cte.OUTPUT_CONTROL)
|
||||
self._write_to_idf_format(file, 'Comma', 'Column Separator', ';')
|
||||
|
||||
|
@ -132,7 +119,7 @@ class CercIdf:
|
|||
def _add_surfaces(self, building, zone_name):
|
||||
# Verify if create building surfaces "by hand" it's faster wwr it's missing
|
||||
zone_name = f'{zone_name}'
|
||||
file = self._output_surfaces
|
||||
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[boundary.parent_surface.type]
|
||||
|
@ -247,7 +234,7 @@ class CercIdf:
|
|||
with open(file_name, 'w', encoding='utf8') as file:
|
||||
for value in schedule.values:
|
||||
file.write(f'{str(value)},\n')
|
||||
file = self._output_file_schedules
|
||||
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')
|
||||
|
@ -266,7 +253,7 @@ class CercIdf:
|
|||
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._output_schedules
|
||||
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')
|
||||
|
@ -286,7 +273,7 @@ class CercIdf:
|
|||
self._write_to_idf_format(file, 'Until: 24:00,0.0', f'Field {counter + 2}', ';')
|
||||
|
||||
def _add_solid_material(self, layer):
|
||||
file = self._output_solid_materials
|
||||
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')
|
||||
|
@ -299,7 +286,7 @@ class CercIdf:
|
|||
self._write_to_idf_format(file, layer.visible_absorptance, 'Visible Absorptance', ';')
|
||||
|
||||
def _add_nomass_material(self, layer):
|
||||
file = self._output_nomass_materials
|
||||
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')
|
||||
|
@ -336,7 +323,7 @@ class CercIdf:
|
|||
glazing_index = self._windows_added_to_idf['glazing_index'] + 1
|
||||
self._windows_added_to_idf[name] = True
|
||||
self._windows_added_to_idf['glazing_index'] = glazing_index # increase the count
|
||||
file = self._output_window_materials
|
||||
file = self._files['window_materials']
|
||||
self._write_to_idf_format(file, idf_cte.WINDOW_MATERIAL)
|
||||
self._write_to_idf_format(file, f'glazing_{glazing_index}', 'Name')
|
||||
self._write_to_idf_format(file, thermal_opening.overall_u_value, 'UFactor')
|
||||
|
@ -356,7 +343,7 @@ class CercIdf:
|
|||
|
||||
if name not in self._constructions_added_to_idf:
|
||||
self._constructions_added_to_idf[name] = True
|
||||
file = self._output_constructions
|
||||
file = self._files['constructions']
|
||||
self._write_to_idf_format(file, idf_cte.CONSTRUCTION)
|
||||
self._write_to_idf_format(file, name, 'Name')
|
||||
eol = ','
|
||||
|
@ -377,13 +364,13 @@ class CercIdf:
|
|||
material_name = f'glazing_{i}'
|
||||
if construction_name not in self._constructions_added_to_idf:
|
||||
self._constructions_added_to_idf[construction_name] = True
|
||||
file = self._output_constructions
|
||||
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, material_name, 'Outside Layer', ';')
|
||||
|
||||
def _add_zone(self, thermal_zone, zone_name):
|
||||
file = self._output_zones
|
||||
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')
|
||||
|
@ -409,7 +396,7 @@ class CercIdf:
|
|||
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._output_occupancy
|
||||
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')
|
||||
|
@ -446,7 +433,7 @@ class CercIdf:
|
|||
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._output_lighting
|
||||
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')
|
||||
|
@ -469,7 +456,7 @@ class CercIdf:
|
|||
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._output_appliances
|
||||
file = self._files['appliances']
|
||||
self._write_to_idf_format(file, idf_cte.APPLIANCES)
|
||||
self._write_to_idf_format(file, f'{zone_name}_appliance', 'Name')
|
||||
self._write_to_idf_format(file, 'Electricity', 'Fuel Type')
|
||||
|
@ -488,7 +475,7 @@ class CercIdf:
|
|||
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
|
||||
file = self._files['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')
|
||||
|
@ -507,7 +494,7 @@ class CercIdf:
|
|||
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
|
||||
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')
|
||||
|
@ -536,60 +523,54 @@ class CercIdf:
|
|||
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):
|
||||
self._output_schedules.flush()
|
||||
with open(self._output_schedules_path, 'r') as file:
|
||||
lines = file.readlines()
|
||||
self._idf_file.writelines(lines)
|
||||
self._output_file_schedules.flush()
|
||||
with open(self._output_file_schedules_path, 'r') as file:
|
||||
lines = file.readlines()
|
||||
self._idf_file.writelines(lines)
|
||||
self._output_solid_materials.flush()
|
||||
with open(self._output_solid_materials_path, 'r') as file:
|
||||
lines = file.readlines()
|
||||
self._idf_file.writelines(lines)
|
||||
self._output_nomass_materials.flush()
|
||||
with open(self._output_nomass_materials_path, 'r') as file:
|
||||
lines = file.readlines()
|
||||
self._idf_file.writelines(lines)
|
||||
self._output_window_materials.flush()
|
||||
with open(self._output_window_materials_path, 'r') as file:
|
||||
lines = file.readlines()
|
||||
self._idf_file.writelines(lines)
|
||||
self._output_constructions.flush()
|
||||
with open(self._output_constructions_path, 'r') as file:
|
||||
lines = file.readlines()
|
||||
self._idf_file.writelines(lines)
|
||||
self._output_zones.flush()
|
||||
with open(self._output_zones_path, 'r') as file:
|
||||
lines = file.readlines()
|
||||
self._idf_file.writelines(lines)
|
||||
self._output_occupancy.flush()
|
||||
with open(self._output_occupancy_path, 'r') as file:
|
||||
lines = file.readlines()
|
||||
self._idf_file.writelines(lines)
|
||||
self._output_lighting.flush()
|
||||
with open(self._output_lighting_path, 'r') as file:
|
||||
lines = file.readlines()
|
||||
self._idf_file.writelines(lines)
|
||||
self._output_appliances.flush()
|
||||
with open(self._output_appliances_path, 'r') as file:
|
||||
lines = file.readlines()
|
||||
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()
|
||||
with open(self._output_surfaces_path, 'r') as file:
|
||||
lines = file.readlines()
|
||||
self._idf_file.writelines(lines)
|
||||
def _add_thermostat(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', ';')
|
||||
|
||||
def _add_heating_system(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', ';')
|
||||
|
||||
def _export(self):
|
||||
for building in self._city.buildings:
|
||||
|
@ -641,6 +622,8 @@ class CercIdf:
|
|||
self._add_appliances(thermal_zone, building.name)
|
||||
self._add_infiltration(thermal_zone, building.name)
|
||||
self._add_ventilation(thermal_zone, building.name)
|
||||
self._add_thermostat(thermal_zone)
|
||||
self._add_heating_system(thermal_zone, building.name)
|
||||
if is_target:
|
||||
self._add_surfaces(building, building.name)
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@ 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'
|
||||
|
||||
|
||||
AUTOCALCULATE = 'autocalculate'
|
||||
|
|
Loading…
Reference in New Issue
Block a user