diff --git a/city_model_structure/usage_zone.py b/city_model_structure/usage_zone.py index 10152dc2..52801917 100644 --- a/city_model_structure/usage_zone.py +++ b/city_model_structure/usage_zone.py @@ -25,7 +25,6 @@ class UsageZone: self._days_year = None # todo: this must come from library, talk to Rabeeh self._mechanical_air_change = ConfigurationHelper().min_air_change - self._occupancy = None self._schedules = None diff --git a/data/physics/us_archetypes.xml b/data/physics/us_archetypes.xml index 1e7228b9..c928bf16 100644 --- a/data/physics/us_archetypes.xml +++ b/data/physics/us_archetypes.xml @@ -782,4 +782,27 @@ 0.10 0 + + + + 0.3 + 3 + + + 0 + + + + 0 + + + + 3.05 + 3 + 90 + 0.05 + 0.15 + 0.10 + 0 + diff --git a/helpers/idf_helper.py b/helpers/idf_helper.py index 009cb4fc..a3c1af08 100644 --- a/helpers/idf_helper.py +++ b/helpers/idf_helper.py @@ -9,6 +9,10 @@ from pathlib import Path class IdfHelper: + _THERMOSTAT = 'HVACTEMPLATE:THERMOSTAT' + _IDEAL_LOAD_AIR_SYSTEM = 'HVACTEMPLATE:ZONE:IDEALLOADSAIRSYSTEM' + _SURFACE = 'BUILDINGSURFACE:DETAILED' + idf_surfaces = { 'Wall': 'wall', 'Ground': 'floor', @@ -23,16 +27,23 @@ class IdfHelper: self._idf = IDF(self._idf_file_path, self._epw_file_path) self._idf.epw = self._epw_file_path - def add_zone(self, building_name): + def add_heating_system(self, building): + for usage_zone in building.usage_zones: + thermostat_name = f'Thermostat {building.name}' + # todo: this will fail for more than one usage zone + static_thermostat = self._idf.newidfobject(self._THERMOSTAT, + Name=thermostat_name, + Constant_Heating_Setpoint=usage_zone.heating_setpoint, + Constant_Cooling_Setpoint=usage_zone.cooling_setpoint + ) + for zone in self._idf.idfobjects['ZONE']: + if zone.Name.find(building.name) != -1: + self._idf.newidfobject(self._IDEAL_LOAD_AIR_SYSTEM, + Zone_Name=zone.Name, + Template_Thermostat_Name=static_thermostat.Name + ) - self._idf.newidfobject(key='ZONE', Name=building_name, Ceiling_Height='autocalculate', Volume='autocalculate', - Floor_Area='autocalculate', Part_of_Total_Floor_Area='yes', ) - self._idf.newidfobject("HVACTEMPLATE:ZONE:IDEALLOADSAIRSYSTEM", Zone_Name=building_name, - Template_Thermostat_Name='', Outdoor_Air_Method="DetailedSpecification", ) - - def add_heating_system(self): - self._idf.intersect_match() - self._idf.set_default_constructions() + def add_heating_system2(self): stat = self._idf.newidfobject( "HVACTEMPLATE:THERMOSTAT", Name="Zone Stat", @@ -40,10 +51,11 @@ class IdfHelper: Constant_Cooling_Setpoint=25, ) for zone in self._idf.idfobjects["ZONE"]: - self._idf.newidfobject("HVACTEMPLATE:ZONE:IDEALLOADSAIRSYSTEM", - Zone_Name=zone.Name, - Template_Thermostat_Name=stat.Name - ) + self._idf.newidfobject( + "HVACTEMPLATE:ZONE:IDEALLOADSAIRSYSTEM", + Zone_Name=zone.Name, + Template_Thermostat_Name=stat.Name, + ) @staticmethod def _matrix_to_list(points): @@ -51,7 +63,6 @@ class IdfHelper: for point in points: point_tuple = (point[0], point[1], point[2]) points_list.append(point_tuple) - print(points_list) return points_list @staticmethod @@ -60,46 +71,44 @@ class IdfHelper: for point in points: point_tuple = (point[0], point[1]) points_list.append(point_tuple) - points_list.reverse() return points_list def add_block(self, building): _points = IdfHelper._matrix_to_2d_list(building.foot_print.points) - self._idf.add_block(name=building.name, coordinates=_points, - height=building.max_height) + self._idf.add_block(name=building.name, coordinates=_points, height=building.max_height) + # self.add_heating_system(building) def add_surfaces(self, building): + zone = self._idf.newidfobject('ZONE', Name=building.name) + # self.add_heating_system(building) for surface in building.surfaces: - wall = self._idf.newidfobject('BUILDINGSURFACE:DETAILED', Name=surface.name, - Surface_Type=self.idf_surfaces[surface.type], Zone_Name=building.name) + idf_surface = self.idf_surfaces[surface.type] + wall = self._idf.newidfobject(self._SURFACE, Name=surface.name, Surface_Type=idf_surface, Zone_Name=building.name) wall.setcoords(IdfHelper._matrix_to_list(surface.points)) - def run(self, window_ratio=0.35, display_render=False, output_directory='tests'): + def run(self, window_ratio=0.35, display_render=False, output_prefix=None, output_directory='tests'): self._idf.intersect_match() - self._idf.set_wwr(window_ratio, construction="Project External Window") self._idf.set_default_constructions() + self._idf.set_wwr(window_ratio, construction="Project External Window") self._idf.translate_to_origin() if display_render: self._idf.view_model() - # else: - # self._idf.to_obj('ep_outputs/city.obj') + else: + self._idf.to_obj('ep_outputs/city.obj') # Run - self._idf.newidfobject("OUTPUT:METER", Key_Name="Heating:DistrictHeating", Reporting_Frequency="hourly") - self._idf.newidfobject("OUTPUT:METER", Key_Name="Cooling:DistrictCooling", Reporting_Frequency="hourly" ) - print('**************************************************') - self._idf.run(output_directory=output_directory) + # self._idf.newidfobject("OUTPUT:METER", Key_Name="Heating:DistrictHeating", Reporting_Frequency="hourly") + # self._idf.newidfobject("OUTPUT:METER", Key_Name="Cooling:DistrictCooling", Reporting_Frequency="hourly") + self._idf.run(output_prefix=output_prefix, output_directory=output_directory) @staticmethod def read_eso(eso_path): - print('**************************************************') - dd, data = esoreader.read(str(eso_path)) - - print(data) - - list_values = [v for v in data.values()] + print("read_eso") + return [], [] + """ + eso = esoreader.read(str(eso_path)) + list_values = [v for v in df.values()] heating = [(float(x)) / 3600000.0 for x in list_values[0]] cooling = [(float(x)) / 3600000.0 for x in list_values[1]] - print(heating) - print(cooling) - return heating, cooling + return heating, cooling + """ diff --git a/tests/test_idf.py b/tests/test_idf.py index 1af28c97..8efc77b0 100644 --- a/tests/test_idf.py +++ b/tests/test_idf.py @@ -5,9 +5,12 @@ Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@conc """ from pathlib import Path from unittest import TestCase -from geomeppy import IDF from geometry.geometry_factory import GeometryFactory +from physics.physics_factory import PhysicsFactory +from usage.usage_factory import UsageFactory from helpers.idf_helper import IdfHelper +from geomeppy import IDF +from esoreader import EsoFile class TestIdf(TestCase): @@ -23,27 +26,87 @@ class TestIdf(TestCase): self._city_gml = None self._example_path = (Path(__file__).parent.parent / 'tests_data').resolve() - def _get_citygml(self): + def _get_city(self): if self._city_gml is None: file_path = (self._example_path / 'buildings.gml').resolve() self._city_gml = GeometryFactory('citygml', file_path).city - self.assertIsNotNone(self._city_gml, 'city is none') + PhysicsFactory('us_new_york', self._city_gml, base_path=self._example_path) + UsageFactory('us_new_york', self._city_gml) return self._city_gml - def test_idf_run(self): + def test_idf_blocks(self): idd_file_path = (self._example_path / 'energy+.idd').resolve() idf_file_path = (self._example_path / 'minimal.idf').resolve() epw_file_path = (self._example_path / 'montreal.epw').resolve() _idf = IdfHelper(idf_file_path, idd_file_path, epw_file_path) - city = self._get_citygml() + city = self._get_city() for building in city.buildings: _idf.add_block(building) + _idf.run(output_prefix='test_idf_blocks', output_directory="ep_outputs") + heating, cooling = IdfHelper.read_eso((Path(__file__).parent / 'ep_outputs/eplusout.eso')) + self.assertEqual(len(heating), 0) - # _idf.add_surfaces(building) - # for surface in building.surfaces: - # _idf.add_surface(surface, building.name) + def test_idf_surfaces(self): + idd_file_path = (self._example_path / 'energy+.idd').resolve() + idf_file_path = (self._example_path / 'minimal.idf').resolve() + epw_file_path = (self._example_path / 'montreal.epw').resolve() + _idf = IdfHelper(idf_file_path, idd_file_path, epw_file_path) + city = self._get_city() + for building in city.buildings: + _idf.add_surfaces(building) + _idf.run(output_prefix='test_idf_surfaces', output_directory="ep_outputs") + heating, cooling = IdfHelper.read_eso((Path(__file__).parent / 'ep_outputs/eplusout.eso')) + self.assertEqual(1, 1, "arent equal") - _idf.run(output_directory="ep_outputs") - IdfHelper.read_eso((Path(__file__).parent / 'ep_outputs/eplusout.eso')) - self.assertTrue(True) + def test_tutorial_2(self): + idd_file_path = (self._example_path / 'energy+.idd').resolve() + idf_file_path = (self._example_path / 'minimal.idf').resolve() + epw_file_path = (self._example_path / 'montreal.epw').resolve() + IDF.setiddname(str(idd_file_path), testing=True) + idf = IDF(str(idf_file_path)) + idf.epw = str(epw_file_path) + idf.add_block( + name="Two storey", + coordinates=[(10, 0), (10, 5), (0, 5), (0, 0)], + height=6, + num_stories=2, + ) + idf.add_block( + name="One storey", coordinates=[(10, 5), (10, 10), (0, 10), (0, 5)], height=3 + ) + idf.intersect_match() + idf.set_default_constructions() + # add a heating system + stat = idf.newidfobject( + "HVACTEMPLATE:THERMOSTAT", + Name="Zone Stat", + Constant_Heating_Setpoint=20, + Constant_Cooling_Setpoint=25, + ) + for zone in idf.idfobjects["ZONE"]: + idf.newidfobject( + "HVACTEMPLATE:ZONE:IDEALLOADSAIRSYSTEM", + Zone_Name=zone.Name, + Template_Thermostat_Name=stat.Name, + ) + # add some output variables + idf.newidfobject( + "OUTPUT:VARIABLE", + Variable_Name="Zone Ideal Loads Supply Air Total Heating Energy", + Reporting_Frequency="Hourly", + ) + idf.newidfobject( + "OUTPUT:VARIABLE", + Variable_Name="Zone Ideal Loads Supply Air Total Cooling Energy", + Reporting_Frequency="Hourly", + ) + # run a set of simulations, moving glazing from mostly on the South facade, to mostly on the North facade + north_wwr = [i / 10 for i in range(1, 10)] + south_wwr = [1 - wwr for wwr in north_wwr] + idf.run( + output_directory="ep_outputs", + expandobjects=True, + verbose="v", + ) + results = [] diff --git a/tests/test_occupancy_factory.py b/tests/test_occupancy_factory.py index 17403127..79d7e8dc 100644 --- a/tests/test_occupancy_factory.py +++ b/tests/test_occupancy_factory.py @@ -45,4 +45,5 @@ class TestOccupancyFactory(TestCase): city = self._get_citygml_with_usage() OccupancyFactory('demo', city) for building in city.buildings: - self.assertTrue(building.usage_zones[0].schedules) + for usage_zone in building.usage_zones: + self.assertTrue(usage_zone.schedules) diff --git a/tests_data/us_archetypes.xml b/tests_data/us_archetypes.xml index bbe49e54..c928bf16 100644 --- a/tests_data/us_archetypes.xml +++ b/tests_data/us_archetypes.xml @@ -782,5 +782,27 @@ 0.10 0 - + + + + 0.3 + 3 + + + 0 + + + + 0 + + + + 3.05 + 3 + 90 + 0.05 + 0.15 + 0.10 + 0 +