diff --git a/exports/formats/idf.py b/exports/formats/idf.py index e09d401f..85644762 100644 --- a/exports/formats/idf.py +++ b/exports/formats/idf.py @@ -160,14 +160,19 @@ class Idf: _kwargs = {'Name': f'{schedule_type} schedules {usage}', 'Schedule_Type_Limits_Name': self.idf_type_limits[schedules[0].data_type], 'Field_1': 'Through: 12/31'} + counter = 1 for j, schedule in enumerate(schedules): _val = schedule.values _new_field = '' for day_type in schedule.day_types: _new_field += f' {self.idf_day_types[day_type]}' _kwargs[f'Field_{j * 25 + 2}'] = f'For:{_new_field}' + counter += 1 for i in range(0, len(_val)): _kwargs[f'Field_{j * 25 + 3 + i}'] = f'Until: {i + 1:02d}:00,{_val[i]}' + counter += 1 + _kwargs[f'Field_{counter + 1}'] = f'For AllOtherDays' + _kwargs[f'Field_{counter + 2}'] = f'Until: 24:00,0.0' self._idf.newidfobject(self._COMPACT_SCHEDULE, **_kwargs) def _write_schedules_file(self, usage, schedule): @@ -205,10 +210,28 @@ class Idf: _infiltration_values.append(thermal_zone.infiltration_rate_system_on) _schedule.values = _infiltration_values _infiltration_schedules.append(_schedule) - for schedule in self._idf.idfobjects[self._HOURLY_SCHEDULE]: - if schedule.Name == f'Infiltration schedules {thermal_zone.usage}': - return - return self._add_standard_compact_hourly_schedule(thermal_zone.usage, 'Infiltration', _infiltration_schedules) + for schedule in self._idf.idfobjects[self._HOURLY_SCHEDULE]: + if schedule.Name == f'Infiltration schedules {thermal_zone.usage}': + return + return self._add_standard_compact_hourly_schedule(thermal_zone.usage, 'Infiltration', _infiltration_schedules) + + def _add_people_activity_level_schedules(self, thermal_zone): + _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 + for schedule in self._idf.idfobjects[self._HOURLY_SCHEDULE]: + if schedule.Name == f'Activity Level schedules {thermal_zone.usage}': + return + _kwargs = {'Name': f'Activity Level schedules {thermal_zone.usage}', + 'Schedule_Type_Limits_Name': self.idf_type_limits[cte.ANY_NUMBER], + 'Field_1': 'Through: 12/31', + 'Field_2': 'For AllDays', + 'Field_3': f'Until: 24:00,{_total_heat}'} + self._idf.newidfobject(self._COMPACT_SCHEDULE, **_kwargs) + return def _add_schedules(self, usage, schedule_type, new_schedules, schedule_from_file=False): if schedule_from_file: @@ -302,13 +325,9 @@ class Idf: def _add_occupancy(self, thermal_zone): number_of_people = thermal_zone.occupancy.occupancy_density * thermal_zone.total_floor_area - print('aaaaaaaa', thermal_zone.occupancy.sensible_radiative_internal_gain) - print(thermal_zone.occupancy.sensible_convective_internal_gain) - print(thermal_zone.occupancy.latent_internal_gain) fraction_radiant = thermal_zone.occupancy.sensible_radiative_internal_gain / \ (thermal_zone.occupancy.sensible_radiative_internal_gain + - thermal_zone.occupancy.sensible_convective_internal_gain + - thermal_zone.occupancy.latent_internal_gain) + thermal_zone.occupancy.sensible_convective_internal_gain) self._idf.newidfobject(self._PEOPLE, Name=f'{thermal_zone.id}_occupancy', Zone_or_ZoneList_Name=thermal_zone.id, @@ -316,7 +335,7 @@ class Idf: Number_of_People_Calculation_Method="People", Number_of_People=number_of_people, Fraction_Radiant=fraction_radiant, - Activity_Level_Schedule_Name=f'Occupancy schedules {thermal_zone.usage}' + Activity_Level_Schedule_Name=f'Activity Level schedules {thermal_zone.usage}' ) def _add_infiltration(self, thermal_zone): @@ -363,12 +382,11 @@ class Idf: self._add_window_construction_and_material(thermal_opening) usage = thermal_zone.usage self._add_infiltration_schedules(thermal_zone) - # todo: why are there schedules unused? - self._add_schedules(usage, 'Lighting', thermal_zone.lighting.schedules) - self._add_schedules(usage, 'Occupancy', thermal_zone.occupancy.occupancy_schedules, schedule_from_file=False) + self._add_schedules(usage, 'Occupancy', thermal_zone.occupancy.occupancy_schedules, schedule_from_file=True) 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, 'Cooling thermostat', thermal_zone.thermal_control.cooling_set_point_schedules) + self._add_people_activity_level_schedules(thermal_zone) self._add_zone(thermal_zone) self._add_heating_system(thermal_zone) @@ -397,7 +415,7 @@ class Idf: """ Start the energy plus simulation """ - self._idf.run(expandobjects=True, readvars=True, output_directory=self._output_path, + self._idf.run(expandobjects=False, readvars=True, output_directory=self._output_path, output_prefix=f'{self._city.name}_') def _add_block(self, building): @@ -422,15 +440,28 @@ class Idf: for thermal_zone in internal_zone.thermal_zones: for boundary in thermal_zone.thermal_boundaries: idf_surface_type = self.idf_surfaces[boundary.parent_surface.type] + outside_boundary_condition = 'Outdoors' + sun_exposure = 'SunExposed' + wind_exposure = 'WindExposed' + if boundary.parent_surface.type == cte.GROUND: + outside_boundary_condition = 'Ground' + sun_exposure = 'NoSun' + wind_exposure = 'NoWind' if boundary.vegetation is not None: construction_name = f'{boundary.construction_name}_{boundary.vegetation.name}' else: construction_name = boundary.construction_name + print(outside_boundary_condition, sun_exposure, wind_exposure) surface = self._idf.newidfobject(self._SURFACE, Name=f'{boundary.parent_surface.name}', - Surface_Type=idf_surface_type, Zone_Name=thermal_zone.id, - Construction_Name=construction_name) + Surface_Type=idf_surface_type, + Zone_Name=thermal_zone.id, + Construction_Name=construction_name, + Outside_Boundary_Condition=outside_boundary_condition, + Sun_Exposure=sun_exposure, + Wind_Exposure=wind_exposure) coordinates = self._matrix_to_list(boundary.parent_surface.solid_polygon.coordinates, self._city.lower_corner) + surface.setcoords(coordinates) self._add_windows(boundary) diff --git a/helpers/constants.py b/helpers/constants.py index 1e9f0675..630a71f9 100644 --- a/helpers/constants.py +++ b/helpers/constants.py @@ -117,6 +117,7 @@ COOLING_SET_POINT = 'ClgSetPt' HEATING_SET_POINT = 'HtgSetPt' EQUIPMENT = 'Equipment' ACTIVITY = 'Activity' +PEOPLE_ACTIVITY_LEVEL = 'People Activity Level' # Geometry EPSILON = 0.0000001 diff --git a/imports/usage/comnet_usage_parameters.py b/imports/usage/comnet_usage_parameters.py index 5f22994e..87eae088 100644 --- a/imports/usage/comnet_usage_parameters.py +++ b/imports/usage/comnet_usage_parameters.py @@ -232,13 +232,13 @@ class ComnetUsageParameters: _occupancy.occupancy_density = archetype.occupancy.occupancy_density * cte.METERS_TO_FEET**2 _occupancy.sensible_radiative_internal_gain = archetype.occupancy.sensible_radiative_internal_gain \ * archetype.occupancy.occupancy_density \ - * cte.BTU_H_TO_WATTS + * cte.METERS_TO_FEET**2 * cte.BTU_H_TO_WATTS _occupancy.latent_internal_gain = archetype.occupancy.latent_internal_gain \ * archetype.occupancy.occupancy_density \ - * cte.BTU_H_TO_WATTS + * cte.METERS_TO_FEET**2 * cte.BTU_H_TO_WATTS _occupancy.sensible_convective_internal_gain = archetype.occupancy.sensible_convective_internal_gain \ * archetype.occupancy.occupancy_density \ - * cte.BTU_H_TO_WATTS + * cte.METERS_TO_FEET**2 * cte.BTU_H_TO_WATTS _occupancy.occupancy_schedules = archetype.occupancy.occupancy_schedules usage_zone.occupancy = _occupancy _lighting = Lighting()