def test_to_from_dfpkl_methods(): """Test the to/from dfpkl methods.""" pts_1 = (Point3D(0, 0, 3), Point3D(0, 10, 3), Point3D(10, 10, 3), Point3D(10, 0, 3)) pts_2 = (Point3D(10, 0, 3), Point3D(10, 10, 3), Point3D(20, 10, 3), Point3D(20, 0, 3)) pts_3 = (Point3D(0, 10, 3), Point3D(0, 20, 3), Point3D(10, 20, 3), Point3D(10, 10, 3)) pts_4 = (Point3D(10, 10, 3), Point3D(10, 20, 3), Point3D(20, 20, 3), Point3D(20, 10, 3)) room2d_1 = Room2D('Office1', Face3D(pts_1), 3) room2d_2 = Room2D('Office2', Face3D(pts_2), 3) room2d_3 = Room2D('Office3', Face3D(pts_3), 3) room2d_4 = Room2D('Office4', Face3D(pts_4), 3) story = Story('OfficeFloor', [room2d_1, room2d_2, room2d_3, room2d_4]) story.solve_room_2d_adjacency(0.01) story.set_outdoor_window_parameters(SimpleWindowRatio(0.4)) story.multiplier = 4 building = Building('OfficeBuilding', [story]) tree_canopy_geo1 = Face3D.from_regular_polygon(6, 6, Plane(o=Point3D(5, -10, 6))) tree_canopy_geo2 = Face3D.from_regular_polygon(6, 2, Plane(o=Point3D(-5, -10, 3))) tree_canopy = ContextShade('TreeCanopy', [tree_canopy_geo1, tree_canopy_geo2]) model = Model('NewDevelopment', [building], [tree_canopy]) model_dfpkl = model.to_dfpkl('test') assert os.path.isfile(model_dfpkl) new_model = Model.from_dfpkl(model_dfpkl) assert isinstance(new_model, Model) os.remove(model_dfpkl)
def test_scale(): """Test the Model scale method.""" pts_1 = (Point3D(0, 0, 3), Point3D(10, 0, 3), Point3D(10, 10, 3), Point3D(0, 10, 3)) pts_2 = (Point3D(10, 0, 3), Point3D(20, 0, 3), Point3D(20, 10, 3), Point3D(10, 10, 3)) room2d_1 = Room2D('Office1', Face3D(pts_1), 3) room2d_2 = Room2D('Office2', Face3D(pts_2), 3) story = Story('OfficeFloor', [room2d_1, room2d_2]) story.solve_room_2d_adjacency(0.01) story.multiplier = 4 building = Building('OfficeBuilding', [story]) awning_geo1 = Face3D.from_rectangle(6, 6, Plane(o=Point3D(5, -10, 6))) awning_geo2 = Face3D.from_rectangle(2, 2, Plane(o=Point3D(-5, -10, 3))) awning_canopy_1 = ContextShade('AwningCanopy1', [awning_geo1]) awning_canopy_2 = ContextShade('AwningCanopy2', [awning_geo2]) model = Model('NewDevelopment', [building], [awning_canopy_1, awning_canopy_2]) new_m = model.duplicate() new_m.scale(2) assert new_m.buildings[0].unique_stories[0].room_2ds[0].floor_geometry[0] == Point3D(0, 0, 6) assert new_m.buildings[0].unique_stories[0].room_2ds[0].floor_geometry[1] == Point3D(20, 0, 6) assert new_m.buildings[0].unique_stories[0].room_2ds[0].floor_geometry[2] == Point3D(20, 20, 6) assert new_m.buildings[0].unique_stories[0].room_2ds[0].floor_geometry[3] == Point3D(0, 20, 6) assert new_m.buildings[0].unique_stories[0].room_2ds[1].floor_geometry[0] == Point3D(20, 0, 6) assert new_m.buildings[0].unique_stories[0].room_2ds[1].floor_geometry[1] == Point3D(40, 0, 6) assert new_m.buildings[0].unique_stories[0].room_2ds[1].floor_geometry[2] == Point3D(40, 20, 6) assert new_m.buildings[0].unique_stories[0].room_2ds[1].floor_geometry[3] == Point3D(20, 20, 6) assert new_m.buildings[0].floor_area == building.floor_area * 2 ** 2 assert new_m.context_shades[0][0][0] == Point3D(10, -20, 12) assert new_m.context_shades[1][0][0] == Point3D(-10, -20, 6)
def test_reflect(): """Test the Model reflect method.""" pts = (Point3D(1, 1, 2), Point3D(2, 1, 2), Point3D(2, 2, 2), Point3D(1, 2, 2)) plane = Plane(Vector3D(0, 0, 1), Point3D(0, 0, 2)) room = Room2D('SquareShoebox', Face3D(pts, plane), 3) story = Story('OfficeFloor', [room]) story.multiplier = 4 building = Building('OfficeBuilding', [story]) pts = (Point3D(1, 1, 2), Point3D(2, 1, 2), Point3D(2, 2, 2), Point3D(1, 2, 2)) plane = Plane(Vector3D(0, 0, 1), Point3D(0, 0, 2)) awning_canopy = ContextShade('AwningCanopy', [Face3D(pts, plane)]) model = Model('NewDevelopment', [building], [awning_canopy]) origin_1 = Point3D(1, 0, 2) normal_1 = Vector3D(1, 0, 0) plane_1 = Plane(normal_1, origin_1) test_1 = model.duplicate() test_1.reflect(plane_1) assert test_1.buildings[0].unique_stories[0].room_2ds[0].floor_geometry[-1].x == pytest.approx(1, rel=1e-3) assert test_1.buildings[0].unique_stories[0].room_2ds[0].floor_geometry[-1].y == pytest.approx(1, rel=1e-3) assert test_1.buildings[0].unique_stories[0].room_2ds[0].floor_geometry[-1].z == pytest.approx(2, rel=1e-3) assert test_1.buildings[0].unique_stories[0].room_2ds[0].floor_geometry[1].x == pytest.approx(0, rel=1e-3) assert test_1.buildings[0].unique_stories[0].room_2ds[0].floor_geometry[1].y == pytest.approx(2, rel=1e-3) assert test_1.buildings[0].unique_stories[0].room_2ds[0].floor_geometry[1].z == pytest.approx(2, rel=1e-3) assert test_1.context_shades[0][0][-1].x == pytest.approx(1, rel=1e-3) assert test_1.context_shades[0][0][-1].y == pytest.approx(1, rel=1e-3) assert test_1.context_shades[0][0][-1].z == pytest.approx(2, rel=1e-3) assert test_1.context_shades[0][0][1].x == pytest.approx(0, rel=1e-3) assert test_1.context_shades[0][0][1].y == pytest.approx(2, rel=1e-3) assert test_1.context_shades[0][0][1].z == pytest.approx(2, rel=1e-3)
def test_to_honeybee_multiple_models(): """Test to_honeybee with multiple honeybee models.""" pts_1 = (Point3D(0, 0, 3), Point3D(10, 0, 3), Point3D(10, 10, 3), Point3D(0, 10, 3)) pts_2 = (Point3D(10, 0, 3), Point3D(20, 0, 3), Point3D(20, 10, 3), Point3D(10, 10, 3)) pts_3 = (Point3D(0, 20, 3), Point3D(20, 20, 3), Point3D(20, 30, 3), Point3D(0, 30, 3)) room2d_1 = Room2D('Office1', Face3D(pts_1), 3) room2d_2 = Room2D('Office2', Face3D(pts_2), 3) room2d_3 = Room2D('Office3', Face3D(pts_3), 3) story_big = Story('OfficeFloorBig', [room2d_3]) story = Story('OfficeFloor', [room2d_1, room2d_2]) story.solve_room_2d_adjacency(0.01) story.set_outdoor_window_parameters(SimpleWindowRatio(0.4)) story.multiplier = 4 building = Building('OfficeBuilding', [story]) story_big.set_outdoor_window_parameters(SimpleWindowRatio(0.4)) story_big.multiplier = 4 building_big = Building('OfficeBuildingBig', [story_big]) tree_canopy_geo1 = Face3D.from_regular_polygon(6, 6, Plane(o=Point3D(5, -10, 6))) tree_canopy_geo2 = Face3D.from_regular_polygon(6, 2, Plane(o=Point3D(-5, -10, 3))) tree_canopy = ContextShade('TreeCanopy', [tree_canopy_geo1, tree_canopy_geo2]) model = Model('NewDevelopment', [building, building_big], [tree_canopy]) hb_models = model.to_honeybee('Building', 10, False, tolerance=0.01) assert len(hb_models) == 2 assert isinstance(hb_models[0], hb_model.Model) assert isinstance(hb_models[-1], hb_model.Model) assert len(hb_models[-1].rooms) == 4 assert len(hb_models[-1].rooms[-1]) == 6 assert hb_models[-1].rooms[-1].volume == 600 assert hb_models[-1].rooms[-1].floor_area == 200 assert hb_models[-1].rooms[-1].exterior_wall_area == 180 assert len(hb_models[0].orphaned_shades) == 6 assert len(hb_models[-1].orphaned_shades) == 6
def test_geojson_coordinates_to_face3d(): """Test conversion of geojson nested list to face3d.""" # Set constants origin_lon_lat = (-70.0, 42.0) convert_facs = meters_to_long_lat_factors(origin_lon_lat) convert_facs = (1 / convert_facs[0], 1 / convert_facs[1]) # Test a Polygon geojson_polygon_coords = {'coordinates':[ [[-70.0, 42.0], [-69.99997578750273, 42.0], [-69.99997578750273, 42.00001799339205], [-70.0, 42.00001799339205], [-70.0, 42.0]]]} face3d = Model._geojson_coordinates_to_face3d( geojson_polygon_coords['coordinates'], origin_lon_lat, convert_facs) poly2d = Polygon2D([Point2D(v[0], v[1]) for v in face3d.vertices]) # Test that we get single polygon test_poly2d = Polygon2D( [Point2D(0, 0), Point2D(2, 0), Point2D(2, 2), Point2D(0, 2)]) # Check length assert len(poly2d.vertices) == len(test_poly2d.vertices) # Check equivalence assert poly2d.is_equivalent(test_poly2d, 1e-5) # Test a Polygon w/ holes geojson_polygon_coords = {'coordinates':[ [[-70.0, 42.0], [-69.99997578750273, 42.0], [-69.99997578750273, 42.00001799339205], [-70.0, 42.00001799339205], [-70.0, 42.0]], [[-70.0, 42.0], [-69.99997578750273, 42.00001799339205], [-70.0, 42.00001799339205], [-70.0, 42.0]]]} face3d = Model._geojson_coordinates_to_face3d( geojson_polygon_coords['coordinates'], origin_lon_lat, convert_facs) # Check if hole exists assert face3d.has_holes # Convert to polygon polyhole2d = Polygon2D([Point2D(v[0], v[1]) for v in face3d.holes[0]]) # Test that we get single polygon test_polyhole2d = Polygon2D([Point2D(0, 0), Point2D(2, 2), Point2D(0, 2)]) # Check length assert len(polyhole2d.vertices) == len(test_polyhole2d.vertices) # Check equivalence assert polyhole2d.is_equivalent(test_polyhole2d, 1e-5)
def test_model_properties_setability(): """Test the setting of properties on the Model.""" pts_1 = (Point3D(0, 0, 3), Point3D(0, 10, 3), Point3D(10, 10, 3), Point3D(10, 0, 3)) pts_2 = (Point3D(10, 0, 3), Point3D(10, 10, 3), Point3D(20, 10, 3), Point3D(20, 0, 3)) pts_3 = (Point3D(0, 10, 3), Point3D(0, 20, 3), Point3D(10, 20, 3), Point3D(10, 10, 3)) pts_4 = (Point3D(10, 10, 3), Point3D(10, 20, 3), Point3D(20, 20, 3), Point3D(20, 10, 3)) room2d_1 = Room2D('Office1', Face3D(pts_1), 3) room2d_2 = Room2D('Office2', Face3D(pts_2), 3) room2d_3 = Room2D('Office3', Face3D(pts_3), 3) room2d_4 = Room2D('Office4', Face3D(pts_4), 3) story = Story('OfficeFloor', [room2d_1, room2d_2, room2d_3, room2d_4]) story.solve_room_2d_adjacency(0.01) story.set_outdoor_window_parameters(SimpleWindowRatio(0.4)) story.multiplier = 4 building = Building('OfficeBuilding', [story]) model = Model('NewDevelopment', [building]) model.to_rectangular_windows() model.display_name = 'TestBuilding' assert model.display_name == 'TestBuilding' model.units = 'Feet' assert model.units == 'Feet' model.tolerance = 0.1 assert model.tolerance == 0.1 model.angle_tolerance = 0.01 assert model.angle_tolerance == 0.01 model.tolerance = 0.01 assert model.tolerance == 0.01
def test_to_geojson(): """Test the Model to_geojson method.""" pts_1 = (Point3D(50, 50, 3), Point3D(60, 50, 3), Point3D(60, 60, 3), Point3D(50, 60, 3)) pts_2 = (Point3D(60, 50, 3), Point3D(70, 50, 3), Point3D(70, 60, 3), Point3D(60, 60, 3)) pts_3 = (Point3D(50, 70, 3), Point3D(70, 70, 3), Point3D(70, 80, 3), Point3D(50, 80, 3)) room2d_1 = Room2D('Residence1', Face3D(pts_1), 3) room2d_2 = Room2D('Residence2', Face3D(pts_2), 3) room2d_3 = Room2D('Retail', Face3D(pts_3), 3) story_big = Story('RetailFloor', [room2d_3]) story = Story('ResidenceFloor', [room2d_1, room2d_2]) story.solve_room_2d_adjacency(0.01) story.set_outdoor_window_parameters(SimpleWindowRatio(0.4)) story.multiplier = 3 building = Building('ResidenceBuilding', [story]) story_big.set_outdoor_window_parameters(SimpleWindowRatio(0.4)) story_big.multiplier = 1 building_big = Building('RetailBuildingBig', [story_big]) pts_1 = (Point3D(0, 0, 3), Point3D(0, 5, 3), Point3D(15, 5, 3), Point3D(15, 0, 3)) pts_2 = (Point3D(15, 0, 3), Point3D(15, 15, 3), Point3D(20, 15, 3), Point3D(20, 0, 3)) pts_3 = (Point3D(0, 5, 3), Point3D(0, 20, 3), Point3D(5, 20, 3), Point3D(5, 5, 3)) pts_4 = (Point3D(5, 15, 3), Point3D(5, 20, 3), Point3D(20, 20, 3), Point3D(20, 15, 3)) pts_5 = (Point3D(-5, -5, 3), Point3D(-10, -5, 3), Point3D(-10, -10, 3), Point3D(-5, -10, 3)) room2d_1 = Room2D('Office1', Face3D(pts_1), 3) room2d_2 = Room2D('Office2', Face3D(pts_2), 3) room2d_3 = Room2D('Office3', Face3D(pts_3), 3) room2d_4 = Room2D('Office4', Face3D(pts_4), 3) room2d_5 = Room2D('Office5', Face3D(pts_5), 3) int_rms = Room2D.intersect_adjacency( [room2d_1, room2d_2, room2d_3, room2d_4, room2d_5], 0.01) story = Story('OfficeFloor', int_rms) story.rotate_xy(5, Point3D(0, 0, 0)) story.solve_room_2d_adjacency(0.01) story.set_outdoor_window_parameters(SimpleWindowRatio(0.4)) story.multiplier = 5 building_mult = Building('OfficeBuilding', [story]) tree_canopy_geo1 = Face3D.from_regular_polygon(6, 6, Plane(o=Point3D(5, -10, 6))) tree_canopy_geo2 = Face3D.from_regular_polygon(6, 2, Plane(o=Point3D(-5, -10, 3))) tree_canopy = ContextShade('TreeCanopy', [tree_canopy_geo1, tree_canopy_geo2]) model = Model('TestGeoJSON', [building, building_big, building_mult], [tree_canopy]) location = Location('Boston', 'MA', 'USA', 42.366151, -71.019357) geojson_folder = './tests/geojson/' model.to_geojson(location, folder=geojson_folder) geo_fp = os.path.join( geojson_folder, model.identifier, '{}.geojson'.format(model.identifier)) assert os.path.isfile(geo_fp) nukedir(os.path.join(geojson_folder, model.identifier), True)
def validate_model(model_json): """Validate a Model JSON file against the Dragonfly schema. \n Args: model_json: Full path to a Model JSON file. """ try: assert os.path.isfile(model_json), 'No JSON file found at {}.'.format( model_json) # validate the Model JSON click.echo('Validating Model JSON ...') schema_model.Model.parse_file(model_json) click.echo('Pydantic validation passed.') with open(model_json) as json_file: data = json.load(json_file) parsed_model = Model.from_dict(data) parsed_model.check_missing_adjacencies(raise_exception=True) click.echo('Python re-serialization passed.') click.echo('Congratulations! Your Model JSON is valid!') except Exception as e: _logger.exception('Model validation failed.\n{}'.format(e)) sys.exit(1) else: sys.exit(0)
def test_to_urbanopt_electric_network(): """Test the Model.to.urbanopt method with an ElectricNetwork.""" model_json = './tests/json/buffalo_test_district.dfjson' with open(model_json) as json_file: data = json.load(json_file) model = Model.from_dict(data) network_json = './tests/json/buffalo_electric_grid.json' with open(network_json) as json_file: data = json.load(json_file) network = ElectricalNetwork.from_dict(data) # create the urbanopt folder location = Location('Buffalo', 'NY', 'USA', 42.813153, -78.852466) sim_folder = './tests/urbanopt_model_buffalo' geojson, hb_model_jsons, hb_models = \ model.to.urbanopt(model, location, electrical_network=network, folder=sim_folder) # check that the appropriate files were generated assert os.path.isfile(geojson) for model_json in hb_model_jsons: assert os.path.isfile(model_json) for h_model in hb_models: assert isinstance(h_model, hb_model.Model) assert os.path.isfile(os.path.join(sim_folder, 'electrical_database.json')) # clean up the files nukedir(sim_folder, True)
def validate_model(model_json, output_file): """Validate a Model JSON file against the Dragonfly schema. \b Args: model_json: Full path to a Model JSON file. """ try: # re-serialize the Model to make sure no errors are found in re-serialization click.echo( 'Validating Model using dragonfly-core=={} and dragonfly-schema=={}' .format(folders.dragonfly_core_version_str, folders.dragonfly_schema_version_str)) parsed_model = Model.from_dfjson(model_json) click.echo('Re-serialization passed.') # perform several other checks for key dragonfly model schema rules report = parsed_model.check_all(raise_exception=False) click.echo('Geometry and identifier checks completed.') # check the report and write the summary of errors if report == '': output_file.write('Congratulations! Your Model is valid!') else: error_msg = '\nYour Model is invalid for the following reasons:' output_file.write('\n'.join([error_msg, report])) except Exception as e: _logger.exception('Model validation failed.\n{}'.format(e)) sys.exit(1) else: sys.exit(0)
def simulate_model(model_json, epw_file, sim_par_json, folder, log_file): """Simulate a Dragonfly Model JSON file in the Urban Weather Generator (UWG). \b Args: model_json: Full path to a Dragonfly Model JSON file. epw_file: Full path to an .epw file to be morphed to account for urban heat island effect. """ try: # process the simulation parameters and write new ones if necessary if sim_par_json is None: # generate some default simulation parameters sim_par = UWGSimulationParameter() else: with open(sim_par_json) as json_file: data = json.load(json_file) sim_par = UWGSimulationParameter.from_dict(data) # re-serialize the Dragonfly Model with open(model_json) as json_file: data = json.load(json_file) model = Model.from_dict(data) model.convert_to_units('Meters') # run the model through the UWG uwg_json, urban_epw = run_uwg(model, epw_file, sim_par, folder) if urban_epw is None: raise Exception('Running the Urban Weather Generator failed.') log_file.write(json.dumps({'uwg_json': uwg_json, 'epw': urban_epw})) except Exception as e: _logger.exception('Model translation failed.\n{}'.format(e)) sys.exit(1) else: sys.exit(0)
def test_from_honeybee(): """Test the from_honeybee method of Model objects.""" room_south = Room.from_box('SouthZone', 5, 5, 3, origin=Point3D(0, 0, 0)) room_north = Room.from_box('NorthZone', 5, 5, 3, origin=Point3D(0, 5, 0)) room_up = Room.from_box('UpZone', 5, 5, 3, origin=Point3D(0, 5, 3)) room_south[1].apertures_by_ratio(0.4, 0.01) room_south[3].apertures_by_ratio(0.4, 0.01) room_north[3].apertures_by_ratio(0.4, 0.01) Room.solve_adjacency([room_south, room_north], 0.01) pts = (Point3D(0, -3, 0), Point3D(0, -3, 3), Point3D(1, -3, 3), Point3D(1, -3, 0)) shade = Shade('TestShade', Face3D(pts)) model = hb_model.Model('Test_Building', [room_south, room_north, room_up], orphaned_shades=[shade], tolerance=0.01) model = Model.from_honeybee(model) assert len(model.context_shades) == 1 assert len(model.buildings) == 1 bldg = model.buildings[0] assert bldg.identifier == 'Test_Building' assert len(bldg.unique_stories) == 2 bound_cs = [b for room in bldg.unique_room_2ds for b in room.boundary_conditions if isinstance(b, Surface)] assert len(bound_cs) == 2 assert bound_cs[0].boundary_condition_objects == ('NorthZone..Face4', 'NorthZone') assert bound_cs[1].boundary_condition_objects == ('SouthZone..Face2', 'SouthZone')
def two_buildings(): pts_1 = (Point3D(0, 0, 3), Point3D(10, 0, 3), Point3D(10, 10, 3), Point3D(0, 10, 3)) pts_2 = (Point3D(10, 0, 3), Point3D(20, 0, 3), Point3D(20, 10, 3), Point3D(10, 10, 3)) pts_3 = (Point3D(0, 20, 3), Point3D(20, 20, 3), Point3D(20, 30, 3), Point3D(0, 30, 3)) room2d_1 = Room2D('Office1', Face3D(pts_1), 3) room2d_2 = Room2D('Office2', Face3D(pts_2), 3) room2d_3 = Room2D('Office3', Face3D(pts_3), 3) story_big = Story('OfficeFloorBig', [room2d_3]) story = Story('OfficeFloor', [room2d_1, room2d_2]) story.solve_room_2d_adjacency(0.01) story.set_outdoor_window_parameters(SimpleWindowRatio(0.3)) story.multiplier = 3 building = Building('OfficeBuilding', [story]) building.separate_top_bottom_floors() story_big.set_outdoor_window_parameters(SimpleWindowRatio(0.6)) story_big.multiplier = 4 building_big = Building('OfficeBuildingBig', [story_big]) building_big.separate_top_bottom_floors() tree_canopy_geo1 = Face3D.from_regular_polygon(6, 6, Plane(o=Point3D(5, -10, 6))) tree_canopy_geo2 = Face3D.from_regular_polygon( 6, 2, Plane(o=Point3D(-5, -10, 3))) tree_canopy = ContextShade('TreeCanopy', [tree_canopy_geo1, tree_canopy_geo2]) model = Model('NewDevelopment', [building, building_big], [tree_canopy]) return model
def test_properties(): """Test various properties on the model.""" pts_1 = (Point3D(0, 0, 3), Point3D(10, 0, 3), Point3D(10, 10, 3), Point3D(0, 10, 3)) pts_2 = (Point3D(10, 0, 3), Point3D(20, 0, 3), Point3D(20, 10, 3), Point3D(10, 10, 3)) pts_3 = (Point3D(0, 20, 3), Point3D(20, 20, 3), Point3D(20, 30, 3), Point3D(0, 30, 3)) room2d_1 = Room2D('Office1', Face3D(pts_1), 3) room2d_2 = Room2D('Office2', Face3D(pts_2), 3) room2d_3 = Room2D('Office3', Face3D(pts_3), 3) story_big = Story('OfficeFloorBig', [room2d_3]) story = Story('OfficeFloor', [room2d_1, room2d_2]) story.solve_room_2d_adjacency(0.01) story.set_outdoor_window_parameters(SimpleWindowRatio(0.4)) story.multiplier = 4 building = Building('OfficeBuilding', [story]) story_big.set_outdoor_window_parameters(SimpleWindowRatio(0.4)) story_big.multiplier = 2 building_big = Building('OfficeBuildingBig', [story_big]) model = Model('NewDevelopment', [building, building_big]) assert model.average_story_count == 3 assert model.average_story_count_above_ground == 3 assert model.average_height == 12 assert model.average_height_above_ground == 9 assert model.footprint_area == 100 * 4 assert model.floor_area == (100 * 2 * 4) + (200 * 2) assert model.exterior_wall_area == (90 * 2 * 4) + (180 * 2) assert model.exterior_aperture_area == (90 * 2 * 4 * 0.4) + (180 * 2 * 0.4) assert model.volume == (100 * 2 * 4 * 3) + (200 * 2 * 3)
def test_from_geojson_units_test(): """Test the Model from_geojson method with non-meter units.""" # Load test geojson geojson_folder = os.path.join(os.getcwd(), 'tests', 'geojson') geo_fp = os.path.join(geojson_folder, 'TestGeoJSON.geojson') location = Location('Boston', 'MA', 'USA', 42.366151, -71.019357) model, loc = Model.from_geojson(geo_fp, location=location, units='Feet') # Check the first building bldg1 = [bldg for bldg in model.buildings if bldg.identifier == 'ResidenceBuilding'][0] # Check properties assert bldg1.identifier == 'ResidenceBuilding' assert bldg1.display_name == 'ResidenceBuilding' # Check if area is in feet square m2ft = 1 / hb_model.Model.conversion_factor_to_meters('Feet') sm2sft = m2ft * m2ft assert (600.0 * sm2sft) == pytest.approx(bldg1.floor_area, abs=1e-5) assert (200.0 * sm2sft) == pytest.approx(bldg1.footprint_area, abs=1e-5) assert bldg1.story_count == 3 # Check story assert bldg1.story_count == 3 assert len(bldg1.unique_stories) == 1 for story in bldg1.unique_stories: assert (3.0) == pytest.approx(story.floor_to_floor_height, abs=1e-10)
def test_from_dict_nulls(): """Test the re-serialization of a Model with null extension properties.""" test_json = './tests/json/model_with_nulls.json' with open(test_json) as json_file: data = json.load(json_file) model = Model.from_dict(data) assert isinstance(model, Model)
def test_energy_properties(): """Test the existence of the Model energy properties.""" pts_1 = (Point3D(0, 0, 3), Point3D(0, 10, 3), Point3D(10, 10, 3), Point3D(10, 0, 3)) pts_2 = (Point3D(10, 0, 3), Point3D(10, 10, 3), Point3D(20, 10, 3), Point3D(20, 0, 3)) pts_3 = (Point3D(0, 10, 3), Point3D(0, 20, 3), Point3D(10, 20, 3), Point3D(10, 10, 3)) pts_4 = (Point3D(10, 10, 3), Point3D(10, 20, 3), Point3D(20, 20, 3), Point3D(20, 10, 3)) room2d_1 = Room2D('Office1', Face3D(pts_1), 3) room2d_2 = Room2D('Office2', Face3D(pts_2), 3) room2d_3 = Room2D('Office3', Face3D(pts_3), 3) room2d_4 = Room2D('Office4', Face3D(pts_4), 3) story = Story('OfficeFloor', [room2d_1, room2d_2, room2d_3, room2d_4]) story.solve_room_2d_adjacency(0.01) story.set_outdoor_window_parameters(SimpleWindowRatio(0.4)) story.multiplier = 4 for room in story.room_2ds: room.properties.energy.program_type = office_program room.properties.energy.add_default_ideal_air() building = Building('OfficeBuilding', [story]) tree_canopy_geo1 = Face3D.from_regular_polygon(6, 6, Plane(o=Point3D(5, -10, 6))) tree_canopy_geo2 = Face3D.from_regular_polygon( 6, 2, Plane(o=Point3D(-5, -10, 3))) tree_canopy = ContextShade('TreeCanopy', [tree_canopy_geo1, tree_canopy_geo2]) bright_leaves = ShadeConstruction('Bright Light Leaves', 0.5, 0.5, True) tree_canopy.properties.energy.construction = bright_leaves tree_trans = ScheduleRuleset.from_constant_value('Tree Transmittance', 0.5, schedule_types.fractional) tree_canopy.properties.energy.transmittance_schedule = tree_trans model = Model('NewDevelopment', [building], [tree_canopy]) assert hasattr(model.properties, 'energy') assert isinstance(model.properties.energy, ModelEnergyProperties) assert isinstance(model.properties.host, Model) assert len(model.properties.energy.materials) == 0 for mat in model.properties.energy.materials: assert isinstance(mat, _EnergyMaterialBase) assert len(model.properties.energy.constructions) == 1 for cnst in model.properties.energy.constructions: assert isinstance(cnst, (WindowConstruction, OpaqueConstruction, ShadeConstruction, AirBoundaryConstruction)) assert len(model.properties.energy.shade_constructions) == 1 assert len(model.properties.energy.construction_sets) == 0 assert len(model.properties.energy.schedule_type_limits) == 3 assert len(model.properties.energy.schedules) == 8 assert len(model.properties.energy.shade_schedules) == 1 assert len(model.properties.energy.program_types) == 1
def test_convert_to_units(): """Test the Model convert_to_units method.""" pts_1 = (Point3D(0, 0), Point3D(120, 0), Point3D(120, 120), Point3D(0, 120)) pts_2 = (Point3D(120, 0), Point3D(240, 0), Point3D(240, 120), Point3D(120, 120)) room2d_1 = Room2D('Office1', Face3D(pts_1), 96) room2d_2 = Room2D('Office2', Face3D(pts_2), 96) story = Story('OfficeFloor', [room2d_1, room2d_2]) story.solve_room_2d_adjacency(0.01) story.multiplier = 4 building = Building('OfficeBuilding', [story]) model = Model('NewDevelopment', [building], units='Inches') inches_conversion = hb_model.Model.conversion_factor_to_meters('Inches') model.convert_to_units('Meters') assert room2d_1.floor_area == pytest.approx(120 * 120 * (inches_conversion ** 2), rel=1e-3) assert room2d_1.volume == pytest.approx(120 * 120 * 96 * (inches_conversion ** 3), rel=1e-3) assert model.units == 'Meters'
def test_writer(): """Test the Model writer object.""" pts = (Point3D(50, 50, 3), Point3D(60, 50, 3), Point3D(60, 60, 3), Point3D(50, 60, 3)) bldg = Building.from_footprint('TestBldg', [Face3D(pts)], [5, 4, 3, 3], tolerance=0.01) model = Model('TestModel', [bldg]) writers = [mod for mod in dir(model.to) if not mod.startswith('_')] for writer in writers: assert callable(getattr(model.to, writer))
def test_edit_solve_adjacency(): input_model = './tests/json/sample_revit_model.json' runner = CliRunner() result = runner.invoke(solve_adjacency, [input_model]) assert result.exit_code == 0 result_model = Model.from_dict(json.loads(result.output)) rooms = result_model.buildings[0].unique_room_2ds assert isinstance(rooms[0].boundary_conditions[0], Surface)
def test_model_from_geojson(): input_model = './tests/geojson/TestGeoJSON.geojson' runner = CliRunner() result = runner.invoke(model_from_geojson, [input_model, '-wr', '0.4']) assert result.exit_code == 0 model_dict = json.loads(result.output) df_model = Model.from_dict(model_dict) assert isinstance(df_model, Model)
def test_convert_units(): input_model = './tests/json/sample_revit_model.dfjson' runner = CliRunner() result = runner.invoke(convert_units, [input_model, 'Feet']) assert result.exit_code == 0 model_dict = json.loads(result.output) new_model = Model.from_dict(model_dict) assert new_model.units == 'Feet'
def test_model_add_model(): """Test the addition of one Model to another.""" pts_1 = (Point3D(0, 0, 3), Point3D(0, 10, 3), Point3D(10, 10, 3), Point3D(10, 0, 3)) pts_2 = (Point3D(10, 0, 3), Point3D(10, 10, 3), Point3D(20, 10, 3), Point3D(20, 0, 3)) pts_3 = (Point3D(0, 20, 3), Point3D(0, 30, 3), Point3D(10, 30, 3), Point3D(10, 20, 3)) pts_4 = (Point3D(10, 20, 3), Point3D(10, 30, 3), Point3D(20, 30, 3), Point3D(20, 20, 3)) room2d_1 = Room2D('Office1', Face3D(pts_1), 3) room2d_2 = Room2D('Office2', Face3D(pts_2), 3) room2d_3 = Room2D('Office3', Face3D(pts_3), 3) room2d_4 = Room2D('Office4', Face3D(pts_4), 3) story_1 = Story('OfficeFloor1', [room2d_1, room2d_2]) story_2 = Story('OfficeFloor2', [room2d_3, room2d_4]) story_1.solve_room_2d_adjacency(0.01) story_1.set_outdoor_window_parameters(SimpleWindowRatio(0.4)) story_1.multiplier = 4 story_2.solve_room_2d_adjacency(0.01) story_2.set_outdoor_window_parameters(SimpleWindowRatio(0.4)) story_2.multiplier = 2 building_1 = Building('OfficeBuilding1', [story_1]) building_2 = Building('OfficeBuilding2', [story_2]) tree_canopy_geo1 = Face3D.from_regular_polygon(6, 6, Plane(o=Point3D(5, -10, 6))) tree_canopy_geo2 = Face3D.from_regular_polygon(6, 2, Plane(o=Point3D(-5, -10, 3))) tree_canopy_1 = ContextShade('TreeCanopy1', [tree_canopy_geo1]) tree_canopy_2 = ContextShade('TreeCanopy2', [tree_canopy_geo2]) model_1 = Model('NewDevelopment1', [building_1], [tree_canopy_1]) model_2 = Model('NewDevelopment2', [building_2], [tree_canopy_2]) assert len(model_1.buildings) == 1 assert len(model_1.context_shades) == 1 assert len(model_2.buildings) == 1 assert len(model_2.context_shades) == 1 combined_model = model_1 + model_2 assert len(combined_model.buildings) == 2 assert len(combined_model.context_shades) == 2 assert len(model_1.buildings) == 1 assert len(model_1.context_shades) == 1 model_1 += model_2 assert len(model_1.buildings) == 2 assert len(model_1.context_shades) == 2
def test_windows_by_ratio(): input_model = './tests/json/sample_revit_model.dfjson' runner = CliRunner() result = runner.invoke(windows_by_ratio, [input_model, '0.4', '0.2', '0.6', '0.2']) assert result.exit_code == 0 result_model = Model.from_dict(json.loads(result.output)) rooms = result_model.buildings[0].unique_room_2ds assert rooms[0].window_parameters[0] is not None
def test_dict_to_object(): """Test the dict_to_object method with all geometry objects.""" pts_1 = (Point3D(0, 0, 3), Point3D(0, 10, 3), Point3D(10, 10, 3), Point3D(10, 0, 3)) pts_2 = (Point3D(10, 0, 3), Point3D(10, 10, 3), Point3D(20, 10, 3), Point3D(20, 0, 3)) pts_3 = (Point3D(0, 10, 3), Point3D(0, 20, 3), Point3D(10, 20, 3), Point3D(10, 10, 3)) pts_4 = (Point3D(10, 10, 3), Point3D(10, 20, 3), Point3D(20, 20, 3), Point3D(20, 10, 3)) room2d_1 = Room2D('Office1', Face3D(pts_1), 3) room2d_2 = Room2D('Office2', Face3D(pts_2), 3) room2d_3 = Room2D('Office3', Face3D(pts_3), 3) room2d_4 = Room2D('Office4', Face3D(pts_4), 3) story = Story('Office_Floor', [room2d_1, room2d_2, room2d_3, room2d_4]) story.solve_room_2d_adjacency(0.01) story.set_outdoor_window_parameters(SimpleWindowRatio(0.4)) story.multiplier = 4 building = Building('Office_Building', [story]) tree_canopy_geo1 = Face3D.from_regular_polygon(6, 6, Plane(o=Point3D(5, -10, 6))) tree_canopy_geo2 = Face3D.from_regular_polygon( 6, 2, Plane(o=Point3D(-5, -10, 3))) tree_canopy = ContextShade('Tree_Canopy', [tree_canopy_geo1, tree_canopy_geo2]) model = Model('New_Development', [building], [tree_canopy]) model_dict = model.to_dict() room_dict = room2d_1.to_dict() story_dict = story.to_dict() building_dict = building.to_dict() assert isinstance(dict_to_object(model_dict), Model) assert isinstance(dict_to_object(room_dict), Room2D) assert isinstance(dict_to_object(story_dict), Story) assert isinstance(dict_to_object(building_dict), Building)
def test_check_duplicate_construction_set_identifiers(): """Test the check_duplicate_construction_set_identifiers method.""" pts_1 = (Point3D(0, 0, 3), Point3D(0, 10, 3), Point3D(10, 10, 3), Point3D(10, 0, 3)) pts_2 = (Point3D(10, 0, 3), Point3D(10, 10, 3), Point3D(20, 10, 3), Point3D(20, 0, 3)) room2d_1 = Room2D('Office1', Face3D(pts_1), 3) room2d_2 = Room2D('Office2', Face3D(pts_2), 3) story = Story('OfficeFloor', [room2d_1, room2d_2]) story.solve_room_2d_adjacency(0.01) story.set_outdoor_window_parameters(SimpleWindowRatio(0.4)) story.multiplier = 4 for room in story.room_2ds: room.properties.energy.program_type = office_program room.properties.energy.add_default_ideal_air() building = Building('OfficeBuilding', [story]) building.separate_top_bottom_floors() constr_set = ConstructionSet('Attic Construction Set') polyiso = EnergyMaterial('PolyIso', 0.2, 0.03, 43, 1210, 'MediumRough') roof_constr = OpaqueConstruction('Attic Roof Construction', [roof_membrane, polyiso, wood]) floor_constr = OpaqueConstruction('Attic Floor Construction', [wood, insulation, wood]) constr_set.floor_set.interior_construction = floor_constr constr_set.roof_ceiling_set.exterior_construction = roof_constr building.unique_room_2ds[ -1].properties.energy.construction_set = constr_set building.unique_room_2ds[ -2].properties.energy.construction_set = constr_set tree_canopy_geo1 = Face3D.from_regular_polygon(6, 6, Plane(o=Point3D(5, -10, 6))) tree_canopy_geo2 = Face3D.from_regular_polygon( 6, 2, Plane(o=Point3D(-5, -10, 3))) tree_canopy = ContextShade('TreeCanopy', [tree_canopy_geo1, tree_canopy_geo2]) model = Model('NewDevelopment', [building], [tree_canopy]) assert model.properties.energy.check_duplicate_construction_set_identifiers( False) constr_set2 = ConstructionSet('Attic Construction Set') building.unique_room_2ds[ -2].properties.energy.construction_set = constr_set2 assert not model.properties.energy.check_duplicate_construction_set_identifiers( False) with pytest.raises(ValueError): model.properties.energy.check_duplicate_construction_set_identifiers( True)
def test_from_geojson(): """Test the Model from_geojson method.""" # Load test geojson geojson_folder = os.path.join(os.getcwd(), 'tests', 'geojson') geo_fp = os.path.join(geojson_folder, 'TestGeoJSON.geojson') location = Location('Boston', 'MA', 'USA', 42.366151, -71.019357) model, loc = Model.from_geojson(geo_fp, location=location) # Check model non-geometry properties assert model.identifier == 'TestGeoJSON' assert model.display_name == 'TestGeoJSON' # Check model buildings (features) assert len(model.buildings) == 3, len(model.buildings) # Check the first building bldg1 = [bldg for bldg in model.buildings if bldg.identifier == 'ResidenceBuilding'][0] # Check properties assert bldg1.identifier == 'ResidenceBuilding' assert bldg1.display_name == 'ResidenceBuilding' assert 600.0 == pytest.approx(bldg1.floor_area, abs=1e-5) assert 200.0 == pytest.approx(bldg1.footprint_area, abs=1e-5) assert bldg1.story_count == 3 assert bldg1.unique_stories[0].floor_to_floor_height == pytest.approx(3.0, abs=1e-10) # Check the second building bldg2 = [bldg for bldg in model.buildings if bldg.identifier == 'RetailBuildingBig'][0] # Check properties assert bldg2.identifier == 'RetailBuildingBig' assert bldg2.display_name == 'RetailBuildingBig' assert 200.0 == pytest.approx(bldg2.floor_area, abs=1e-5) assert 200.0 == pytest.approx(bldg2.footprint_area, abs=1e-5) assert bldg2.story_count == 1 assert bldg2.unique_stories[0].floor_to_floor_height == pytest.approx(3.0, abs=1e-10) # Check the third building bldg3 = [bldg for bldg in model.buildings if bldg.identifier == 'OfficeBuilding'][0] # Check properties assert bldg3.identifier == 'OfficeBuilding' assert bldg3.display_name == 'OfficeBuilding' assert 1625.0 == pytest.approx(bldg3.floor_area, abs=1e-5) assert 325.0 == pytest.approx(bldg3.footprint_area, abs=1e-5) assert bldg3.story_count == 5 assert bldg3.unique_stories[0].floor_to_floor_height == pytest.approx(3.0, abs=1e-10)
def test_to_dict(): """Test the Model to_dict method.""" pts_1 = (Point3D(0, 0, 3), Point3D(0, 10, 3), Point3D(10, 10, 3), Point3D(10, 0, 3)) pts_2 = (Point3D(10, 0, 3), Point3D(10, 10, 3), Point3D(20, 10, 3), Point3D(20, 0, 3)) pts_3 = (Point3D(0, 10, 3), Point3D(0, 20, 3), Point3D(10, 20, 3), Point3D(10, 10, 3)) pts_4 = (Point3D(10, 10, 3), Point3D(10, 20, 3), Point3D(20, 20, 3), Point3D(20, 10, 3)) room2d_1 = Room2D('Office1', Face3D(pts_1), 3) room2d_2 = Room2D('Office2', Face3D(pts_2), 3) room2d_3 = Room2D('Office3', Face3D(pts_3), 3) room2d_4 = Room2D('Office4', Face3D(pts_4), 3) story = Story('OfficeFloor', [room2d_1, room2d_2, room2d_3, room2d_4]) story.solve_room_2d_adjacency(0.01) story.set_outdoor_window_parameters(SimpleWindowRatio(0.4)) story.multiplier = 4 building = Building('OfficeBuilding', [story]) tree_canopy_geo1 = Face3D.from_regular_polygon(6, 6, Plane(o=Point3D(5, -10, 6))) tree_canopy_geo2 = Face3D.from_regular_polygon(6, 2, Plane(o=Point3D(-5, -10, 3))) tree_canopy = ContextShade('TreeCanopy', [tree_canopy_geo1, tree_canopy_geo2]) model = Model('NewDevelopment', [building], [tree_canopy]) model.tolerance = 0.01 model.angle_tolerance = 1 model_dict = model.to_dict() assert model_dict['type'] == 'Model' assert model_dict['identifier'] == 'NewDevelopment' assert model_dict['display_name'] == 'NewDevelopment' assert 'buildings' in model_dict assert len(model_dict['buildings']) == 1 assert 'context_shades' in model_dict assert len(model_dict['context_shades']) == 1 assert 'tolerance' in model_dict assert model_dict['tolerance'] == 0.01 assert 'angle_tolerance' in model_dict assert model_dict['angle_tolerance'] == 1 assert 'properties' in model_dict assert model_dict['properties']['type'] == 'ModelProperties'
def solve_adjacency(model_json, adiabatic, included_prop, output_file): """Solve adjacency between Room2Ds of a Model JSON file. This includes 3 steps.\n 1. Remove colinear vertices from the Room2D polygons.\n 2. Intersect adjacent segments of the same Story with one another.\n 3. Set Surface boundary conditions for all matching segments across each Story.\n \n Note that this command removes all existing boundary_conditions, window_parameters, and shading_parameters so it is recommended that this method be used at the beginning of model creation. \n Args: model_json: Full path to a Model JSON file.\n adiabatic: Boolean to note whether adjacencies should be adiabatic. included_prop: List of properties to filter keys that must be included in output JSON. For example ["energy"] will include "energy" key if available. By default, all the keys will be included. To exclude all the keys from extensions, use an empty list. """ try: assert os.path.isfile(model_json), 'No JSON file found at {}.'.format(model_json) # serialize the Model to Python with open(model_json) as json_file: data = json.load(json_file) parsed_model = Model.from_dict(data) # check the Model tolerance assert parsed_model.tolerance != 0, \ 'Model must have a non-zero tolerance to use solve-adjacency.' tol = parsed_model.tolerance # process the adjacency of each story for bldg in parsed_model.buildings: for story in bldg.unique_stories: story.remove_room_2d_colinear_vertices(tol) story.intersect_room_2d_adjacency(tol) adj_info = story.solve_room_2d_adjacency(tol) if adiabatic and ad_bc: for face_pair in adj_info: face_pair[0][0].set_boundary_condition(face_pair[0][1], ad_bc) face_pair[1][0].set_boundary_condition(face_pair[1][1], ad_bc) # write the new model out to the file or stdout output_file.write(json.dumps(parsed_model.to_dict(included_prop))) except Exception as e: _logger.exception('Model solve adjacency failed.\n{}'.format(e)) sys.exit(1) else: sys.exit(0)
def solve_adjacency(model_json, surface, no_intersect, output_file): """Solve adjacency between Room2Ds of a Model JSON file. This involves setting Surface or Adiabatic boundary conditions for all matching segments across each Story. \b If the --intersect option is selected, this will involve involve the following. 1. Remove colinear vertices from the Room2D polygons. 2. Intersect adjacent segments of the same Story with one another. Note that the --intersect option removes all existing boundary_conditions, window_parameters, and shading_parameters. \b Args: model_json: Full path to a Model JSON file. """ try: # serialize the Model and check tolerance parsed_model = Model.from_file(model_json) assert parsed_model.tolerance != 0, \ 'Model must have a non-zero tolerance to use solve-adjacency.' tol = parsed_model.tolerance # intersect adjacencies if requested if not no_intersect: for bldg in parsed_model.buildings: for story in bldg.unique_stories: story.remove_room_2d_colinear_vertices(tol) story.intersect_room_2d_adjacency(tol) # solve the adjacency of each story for bldg in parsed_model.buildings: for story in bldg.unique_stories: adj_info = story.solve_room_2d_adjacency(tol) if not surface and ad_bc: for face_pair in adj_info: face_pair[0][0].set_boundary_condition( face_pair[0][1], ad_bc) face_pair[1][0].set_boundary_condition( face_pair[1][1], ad_bc) # write the new model out to the file or stdout output_file.write(json.dumps(parsed_model.to_dict())) except Exception as e: _logger.exception('Model solve adjacency failed.\n{}'.format(e)) sys.exit(1) else: sys.exit(0)