Changes in idf.
This commit is contained in:
parent
f48d5214f4
commit
9ed8fc61e2
|
@ -11,7 +11,6 @@ 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
|
|
||||||
|
|
||||||
|
|
||||||
class Idf:
|
class Idf:
|
||||||
|
@ -21,7 +20,6 @@ class Idf:
|
||||||
_BUILDING = 'BUILDING'
|
_BUILDING = 'BUILDING'
|
||||||
_ZONE = 'ZONE'
|
_ZONE = 'ZONE'
|
||||||
_LIGHTS = 'LIGHTS'
|
_LIGHTS = 'LIGHTS'
|
||||||
_APPLIANCES = 'OTHEREQUIPMENT'
|
|
||||||
_PEOPLE = 'PEOPLE'
|
_PEOPLE = 'PEOPLE'
|
||||||
_THERMOSTAT = 'HVACTEMPLATE:THERMOSTAT'
|
_THERMOSTAT = 'HVACTEMPLATE:THERMOSTAT'
|
||||||
_IDEAL_LOAD_AIR_SYSTEM = 'HVACTEMPLATE:ZONE:IDEALLOADSAIRSYSTEM'
|
_IDEAL_LOAD_AIR_SYSTEM = 'HVACTEMPLATE:ZONE:IDEALLOADSAIRSYSTEM'
|
||||||
|
@ -276,7 +274,7 @@ class Idf:
|
||||||
def _add_window_construction_and_material(self, thermal_opening):
|
def _add_window_construction_and_material(self, thermal_opening):
|
||||||
for window_material in self._idf.idfobjects[self._WINDOW_MATERIAL_SIMPLE]:
|
for window_material in self._idf.idfobjects[self._WINDOW_MATERIAL_SIMPLE]:
|
||||||
if window_material['UFactor'] == thermal_opening.overall_u_value and \
|
if window_material['UFactor'] == thermal_opening.overall_u_value and \
|
||||||
window_material['Solar_Heat_Gain_Coefficient'] == thermal_opening.g_value:
|
window_material['Solar_Heat_Gain_Coefficient'] == thermal_opening.g_value:
|
||||||
return
|
return
|
||||||
|
|
||||||
order = str(len(self._idf.idfobjects[self._WINDOW_MATERIAL_SIMPLE]) + 1)
|
order = str(len(self._idf.idfobjects[self._WINDOW_MATERIAL_SIMPLE]) + 1)
|
||||||
|
@ -322,7 +320,6 @@ class Idf:
|
||||||
|
|
||||||
def _add_occupancy(self, thermal_zone, zone_name):
|
def _add_occupancy(self, thermal_zone, zone_name):
|
||||||
number_of_people = thermal_zone.occupancy.occupancy_density * thermal_zone.total_floor_area
|
number_of_people = thermal_zone.occupancy.occupancy_density * thermal_zone.total_floor_area
|
||||||
print(thermal_zone.occupancy.occupancy_density)
|
|
||||||
fraction_radiant = 0
|
fraction_radiant = 0
|
||||||
total_sensible = thermal_zone.occupancy.sensible_radiative_internal_gain + \
|
total_sensible = thermal_zone.occupancy.sensible_radiative_internal_gain + \
|
||||||
thermal_zone.occupancy.sensible_convective_internal_gain
|
thermal_zone.occupancy.sensible_convective_internal_gain
|
||||||
|
@ -339,54 +336,6 @@ class Idf:
|
||||||
Activity_Level_Schedule_Name=f'Activity Level schedules {thermal_zone.usage_name}'
|
Activity_Level_Schedule_Name=f'Activity Level schedules {thermal_zone.usage_name}'
|
||||||
)
|
)
|
||||||
|
|
||||||
def _add_lighting(self, thermal_zone: ThermalZone, zone_name: str):
|
|
||||||
fraction_radiant = thermal_zone.lighting.radiative_fraction
|
|
||||||
# todo: fraction visible should come from catalog
|
|
||||||
fraction_visible = 0.3
|
|
||||||
method = 'Watts/Area'
|
|
||||||
factor_size = thermal_zone.total_floor_area / thermal_zone.footprint_area
|
|
||||||
watts_per_zone_floor_area = thermal_zone.lighting.density*factor_size
|
|
||||||
# todo: fraction replaceable should come from catalog
|
|
||||||
fraction_replaceable = 1
|
|
||||||
subcategory = f'ELECTRIC EQUIPMENT#{zone_name}#GeneralLights'
|
|
||||||
|
|
||||||
self._idf.newidfobject(self._LIGHTS,
|
|
||||||
Name=f'{zone_name}_lights',
|
|
||||||
Zone_or_ZoneList_Name=zone_name,
|
|
||||||
Schedule_Name=f'Lighting schedules {thermal_zone.usage_name}',
|
|
||||||
Design_Level_Calculation_Method=method,
|
|
||||||
Watts_per_Zone_Floor_Area=watts_per_zone_floor_area,
|
|
||||||
Fraction_Radiant=fraction_radiant,
|
|
||||||
Fraction_Visible=fraction_visible,
|
|
||||||
Fraction_Replaceable=fraction_replaceable,
|
|
||||||
EndUse_Subcategory=subcategory
|
|
||||||
)
|
|
||||||
|
|
||||||
def _add_appliances(self, thermal_zone, zone_name):
|
|
||||||
fuel_type = 'Electricity'
|
|
||||||
fraction_radiant = thermal_zone.appliances.radiative_fraction
|
|
||||||
fraction_convective = thermal_zone.appliances.convective_fraction
|
|
||||||
fraction_latent = 0
|
|
||||||
method = 'Watts/Area'
|
|
||||||
factor_size = thermal_zone.total_floor_area / thermal_zone.footprint_area
|
|
||||||
watts_per_zone_floor_area = thermal_zone.appliances.density*factor_size
|
|
||||||
print(thermal_zone.appliances.density)
|
|
||||||
print(watts_per_zone_floor_area)
|
|
||||||
subcategory = f'ELECTRIC EQUIPMENT#{zone_name}#InteriorEquipment'
|
|
||||||
# _object = self._idf.newidfobject(self._APPLIANCES)
|
|
||||||
# print(vars(_object))
|
|
||||||
self._idf.newidfobject(self._APPLIANCES,
|
|
||||||
Fuel_Type=fuel_type,
|
|
||||||
Name=f'{zone_name}_appliances',
|
|
||||||
Zone_or_ZoneList_Name=zone_name,
|
|
||||||
Schedule_Name=f'Appliance schedules {thermal_zone.usage_name}',
|
|
||||||
Design_Level_Calculation_Method=method,
|
|
||||||
Power_per_Zone_Floor_Area=watts_per_zone_floor_area,
|
|
||||||
Fraction_Latent=fraction_latent,
|
|
||||||
Fraction_Radiant=fraction_radiant,
|
|
||||||
EndUse_Subcategory=subcategory
|
|
||||||
)
|
|
||||||
|
|
||||||
def _add_infiltration(self, thermal_zone, zone_name):
|
def _add_infiltration(self, thermal_zone, zone_name):
|
||||||
for zone in self._idf.idfobjects["ZONE"]:
|
for zone in self._idf.idfobjects["ZONE"]:
|
||||||
if zone.Name == f'{zone_name}_infiltration':
|
if zone.Name == f'{zone_name}_infiltration':
|
||||||
|
@ -439,23 +388,16 @@ class Idf:
|
||||||
usage = thermal_zone.usage_name
|
usage = thermal_zone.usage_name
|
||||||
if building.name in self._target_buildings or building.name in self._adjacent_buildings:
|
if building.name in self._target_buildings or building.name in self._adjacent_buildings:
|
||||||
self._add_infiltration_schedules(thermal_zone)
|
self._add_infiltration_schedules(thermal_zone)
|
||||||
|
|
||||||
self._add_schedules(usage, 'Occupancy', thermal_zone.occupancy.occupancy_schedules)
|
self._add_schedules(usage, 'Occupancy', thermal_zone.occupancy.occupancy_schedules)
|
||||||
self._add_schedules(usage, 'HVAC AVAIL', thermal_zone.thermal_control.hvac_availability_schedules)
|
self._add_schedules(usage, 'HVAC AVAIL', thermal_zone.thermal_control.hvac_availability_schedules)
|
||||||
self._add_schedules(usage, 'Heating thermostat', thermal_zone.thermal_control.heating_set_point_schedules)
|
self._add_schedules(usage, 'Heating thermostat', thermal_zone.thermal_control.heating_set_point_schedules)
|
||||||
self._add_schedules(usage, 'Cooling thermostat', thermal_zone.thermal_control.cooling_set_point_schedules)
|
self._add_schedules(usage, 'Cooling thermostat', thermal_zone.thermal_control.cooling_set_point_schedules)
|
||||||
self._add_schedules(usage, 'Lighting', thermal_zone.lighting.schedules)
|
|
||||||
self._add_schedules(usage, 'Appliances', thermal_zone.appliances.schedules)
|
|
||||||
|
|
||||||
self._add_people_activity_level_schedules(thermal_zone)
|
self._add_people_activity_level_schedules(thermal_zone)
|
||||||
|
|
||||||
self._add_zone(thermal_zone, building.name)
|
self._add_zone(thermal_zone, building.name)
|
||||||
self._add_heating_system(thermal_zone, building.name)
|
self._add_heating_system(thermal_zone, building.name)
|
||||||
self._add_infiltration(thermal_zone, building.name)
|
self._add_infiltration(thermal_zone, building.name)
|
||||||
self._add_occupancy(thermal_zone, building.name)
|
self._add_occupancy(thermal_zone, building.name)
|
||||||
self._add_lighting(thermal_zone, building.name)
|
|
||||||
self._add_appliances(thermal_zone, building.name)
|
|
||||||
|
|
||||||
if self._export_type == "Surfaces":
|
if self._export_type == "Surfaces":
|
||||||
if building.name in self._target_buildings or building.name in self._adjacent_buildings:
|
if building.name in self._target_buildings or building.name in self._adjacent_buildings:
|
||||||
self._add_surfaces(building, building.name)
|
self._add_surfaces(building, building.name)
|
||||||
|
@ -464,19 +406,24 @@ class Idf:
|
||||||
else:
|
else:
|
||||||
self._add_block(building)
|
self._add_block(building)
|
||||||
# todo: this should change to specific variables per zone to process only the ones in the buildings_to_calculate
|
# todo: this should change to specific variables per zone to process only the ones in the buildings_to_calculate
|
||||||
for _ in self._target_buildings:
|
for building in self._target_buildings:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
self._idf.newidfobject(
|
self._idf.newidfobject(
|
||||||
"OUTPUT:VARIABLE",
|
"OUTPUT:VARIABLE",
|
||||||
Variable_Name="Zone Ideal Loads Supply Air Total Heating Energy",
|
Variable_Name="Zone Ideal Loads Supply Air Total Heating Energy",
|
||||||
Reporting_Frequency="Hourly",
|
Reporting_Frequency="Hourly",
|
||||||
)
|
)
|
||||||
|
|
||||||
self._idf.newidfobject(
|
self._idf.newidfobject(
|
||||||
"OUTPUT:VARIABLE",
|
"OUTPUT:VARIABLE",
|
||||||
Variable_Name="Zone Ideal Loads Supply Air Total Cooling Energy",
|
Variable_Name="Zone Ideal Loads Supply Air Total Cooling Energy",
|
||||||
Reporting_Frequency="Hourly",
|
Reporting_Frequency="Hourly",
|
||||||
|
)
|
||||||
|
|
||||||
|
self._idf.newidfobject(
|
||||||
|
"OUTPUTCONTROL:TABLE:STYLE",
|
||||||
|
Variable_Name="CommaAndHTML, JtoKWH",
|
||||||
)
|
)
|
||||||
|
|
||||||
self._idf.match()
|
self._idf.match()
|
||||||
|
@ -588,7 +535,7 @@ class Idf:
|
||||||
for material in self._idf.idfobjects[self._WINDOW_MATERIAL_SIMPLE]:
|
for material in self._idf.idfobjects[self._WINDOW_MATERIAL_SIMPLE]:
|
||||||
if material['Name'] == glazing:
|
if material['Name'] == glazing:
|
||||||
if material['UFactor'] == opening.overall_u_value and \
|
if material['UFactor'] == opening.overall_u_value and \
|
||||||
material['Solar_Heat_Gain_Coefficient'] == opening.g_value:
|
material['Solar_Heat_Gain_Coefficient'] == opening.g_value:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ class InselMonthlyEnergyBalance(Insel):
|
||||||
self._weather_format = weather_format
|
self._weather_format = weather_format
|
||||||
self._contents = []
|
self._contents = []
|
||||||
self._insel_files_paths = []
|
self._insel_files_paths = []
|
||||||
|
self._sanity_check()
|
||||||
for building in city.buildings:
|
for building in city.buildings:
|
||||||
self._insel_files_paths.append(building.name + '.insel')
|
self._insel_files_paths.append(building.name + '.insel')
|
||||||
file_name_out = building.name + '.out'
|
file_name_out = building.name + '.out'
|
||||||
|
@ -46,7 +47,7 @@ class InselMonthlyEnergyBalance(Insel):
|
||||||
f'Monthly Energy Balance cannot be processed\n')
|
f'Monthly Energy Balance cannot be processed\n')
|
||||||
break
|
break
|
||||||
self._contents.append(
|
self._contents.append(
|
||||||
self.generate_meb_template(building, output_path, self._radiation_calculation_method,self._weather_format)
|
self._generate_meb_template(building, output_path, self._radiation_calculation_method,self._weather_format)
|
||||||
)
|
)
|
||||||
self._export()
|
self._export()
|
||||||
|
|
||||||
|
@ -57,8 +58,30 @@ class InselMonthlyEnergyBalance(Insel):
|
||||||
insel_file.write(content)
|
insel_file.write(content)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def _sanity_check(self):
|
||||||
|
levels_of_detail = self._city.level_of_detail
|
||||||
|
if levels_of_detail.geometry is None:
|
||||||
|
raise Exception(f'Level of detail of geometry not assigned')
|
||||||
|
if levels_of_detail.geometry < 1:
|
||||||
|
raise Exception(f'Level of detail of geometry = {levels_of_detail.geometry}. Required minimum level 1')
|
||||||
|
if levels_of_detail.construction is None:
|
||||||
|
raise Exception(f'Level of detail of construction not assigned')
|
||||||
|
if levels_of_detail.construction < 1:
|
||||||
|
raise Exception(f'Level of detail of construction = {levels_of_detail.construction}. Required minimum level 1')
|
||||||
|
if levels_of_detail.usage is None:
|
||||||
|
raise Exception(f'Level of detail of usage not assigned')
|
||||||
|
if levels_of_detail.usage < 1:
|
||||||
|
raise Exception(f'Level of detail of usage = {levels_of_detail.usage}. Required minimum level 1')
|
||||||
|
for building in self._city.buildings:
|
||||||
|
if cte.MONTH not in building.external_temperature:
|
||||||
|
raise Exception(f'Building {building.name} does not have external temperature assigned')
|
||||||
|
for surface in building.surfaces:
|
||||||
|
if surface.type != cte.GROUND:
|
||||||
|
if cte.MONTH not in surface.global_irradiance:
|
||||||
|
raise Exception(f'Building {building.name} does not have global irradiance on surfaces assigned')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def generate_meb_template(building, insel_outputs_path, radiation_calculation_method, weather_format):
|
def _generate_meb_template(building, insel_outputs_path, radiation_calculation_method, weather_format):
|
||||||
file = ""
|
file = ""
|
||||||
i_block = 1
|
i_block = 1
|
||||||
parameters = ["1", "12", "1"]
|
parameters = ["1", "12", "1"]
|
||||||
|
@ -100,16 +123,38 @@ class InselMonthlyEnergyBalance(Insel):
|
||||||
for ig in usage.internal_gains:
|
for ig in usage.internal_gains:
|
||||||
total_internal_gain += ig.average_internal_gain * (ig.convective_fraction + ig.radiative_fraction)
|
total_internal_gain += ig.average_internal_gain * (ig.convective_fraction + ig.radiative_fraction)
|
||||||
parameters.append(f'{total_internal_gain} % BP(12) #2 Internal gains of zone {i + 1}')
|
parameters.append(f'{total_internal_gain} % BP(12) #2 Internal gains of zone {i + 1}')
|
||||||
parameters.append(f'{usage.thermal_control.mean_heating_set_point} % BP(13) #3 Heating setpoint temperature '
|
parameters.append(f'{usage.thermal_control.mean_heating_set_point+1} % BP(13) #3 Heating setpoint temperature '
|
||||||
f'zone {i + 1} (degree Celsius)')
|
f'zone {i + 1} (degree Celsius)')
|
||||||
parameters.append(f'{usage.thermal_control.heating_set_back} % BP(14) #4 Heating setback temperature '
|
parameters.append(f'{usage.thermal_control.heating_set_back+1} % BP(14) #4 Heating setback temperature '
|
||||||
f'zone {i + 1} (degree Celsius)')
|
f'zone {i + 1} (degree Celsius)')
|
||||||
parameters.append(f'{usage.thermal_control.mean_cooling_set_point + 3} % BP(15) #5 Cooling setpoint temperature '
|
parameters.append(f'{usage.thermal_control.mean_cooling_set_point+4} % BP(15) #5 Cooling setpoint temperature '
|
||||||
f'zone {i + 1} (degree Celsius)')
|
f'zone {i + 1} (degree Celsius)')
|
||||||
parameters.append(f'{usage.hours_day} % BP(16) #6 Usage hours per day zone {i + 1}')
|
parameters.append(f'{usage.hours_day} % BP(16) #6 Usage hours per day zone {i + 1}')
|
||||||
parameters.append(f'{usage.days_year} % BP(17) #7 Usage days per year zone {i + 1}')
|
parameters.append(f'{usage.days_year} % BP(17) #7 Usage days per year zone {i + 1}')
|
||||||
|
|
||||||
ventilation_infiltration = usage.mechanical_air_change + internal_zone.thermal_zones[0].infiltration_rate_system_off
|
ventilation = 0
|
||||||
|
infiltration = 0
|
||||||
|
for schedule in usage.thermal_control.hvac_availability_schedules:
|
||||||
|
ventilation_day = 0
|
||||||
|
infiltration_day = 0
|
||||||
|
for value in schedule.values:
|
||||||
|
if value == 0:
|
||||||
|
infiltration_day += internal_zone.thermal_zones[0].infiltration_rate_system_off / 24
|
||||||
|
ventilation_day += 0
|
||||||
|
else:
|
||||||
|
ventilation_value = usage.mechanical_air_change * value
|
||||||
|
infiltration_value = internal_zone.thermal_zones[0].infiltration_rate_system_off * value
|
||||||
|
if ventilation_value >= infiltration_value:
|
||||||
|
ventilation_day += ventilation_value / 24
|
||||||
|
infiltration_day += 0
|
||||||
|
else:
|
||||||
|
ventilation_day += 0
|
||||||
|
infiltration_day += infiltration_value / 24
|
||||||
|
for day_type in schedule.day_types:
|
||||||
|
infiltration += infiltration_day * cte.DAYS_A_YEAR[day_type] / 365
|
||||||
|
ventilation += ventilation_day * cte.DAYS_A_YEAR[day_type] / 365
|
||||||
|
|
||||||
|
ventilation_infiltration = ventilation + infiltration
|
||||||
parameters.append(f'{ventilation_infiltration} % BP(18) #8 Minimum air change rate zone {i + 1} (ACH)')
|
parameters.append(f'{ventilation_infiltration} % BP(18) #8 Minimum air change rate zone {i + 1} (ACH)')
|
||||||
|
|
||||||
parameters.append(f'{len(thermal_zone.thermal_boundaries)} % Number of surfaces = BP(11+8z) \n'
|
parameters.append(f'{len(thermal_zone.thermal_boundaries)} % Number of surfaces = BP(11+8z) \n'
|
||||||
|
@ -127,7 +172,7 @@ class InselMonthlyEnergyBalance(Insel):
|
||||||
for thermal_boundary in thermal_zone.thermal_boundaries:
|
for thermal_boundary in thermal_zone.thermal_boundaries:
|
||||||
type_code = _CONSTRUCTION_CODE[thermal_boundary.type]
|
type_code = _CONSTRUCTION_CODE[thermal_boundary.type]
|
||||||
wall_area = thermal_boundary.opaque_area * (1 + thermal_boundary.window_ratio)
|
wall_area = thermal_boundary.opaque_area * (1 + thermal_boundary.window_ratio)
|
||||||
if thermal_boundary.type == cte.WALL and thermal_boundary.parent_surface.percentage_shared is not None:
|
if thermal_boundary.type == cte.WALL:
|
||||||
wall_area = wall_area * (1 - thermal_boundary.parent_surface.percentage_shared)
|
wall_area = wall_area * (1 - thermal_boundary.parent_surface.percentage_shared)
|
||||||
window_area = wall_area * thermal_boundary.window_ratio
|
window_area = wall_area * thermal_boundary.window_ratio
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user