From d073f0265e5191f693762db7a4910bb431b7f8b9 Mon Sep 17 00:00:00 2001 From: Guille Date: Thu, 4 Jun 2020 12:47:48 -0400 Subject: [PATCH] Unit test review to include data model changes and code cleaning --- city_model_structure/city.py | 3 - city_model_structure/material.py | 1 - city_model_structure/surface.py | 25 +- city_model_structure/thermal_zone.py | 4 +- city_model_structure/window.py | 1 - physics/physics_factory.py | 7 +- .../us_base_physics_parameters.py | 6 +- .../us_new_york_city_physics_parameters.py | 4 +- .../physics_feeders/us_physics_parameters.py | 4 +- tests/test_geometry_factory.py | 37 +- tests/test_physics_factory.py | 24 +- tests_data/us_archetypes.xml | 786 ++++++++++++++++++ tests_data/us_constructions.xml | 606 ++++++++++++++ 13 files changed, 1457 insertions(+), 51 deletions(-) create mode 100644 tests_data/us_archetypes.xml create mode 100644 tests_data/us_constructions.xml diff --git a/city_model_structure/city.py b/city_model_structure/city.py index 5002de02..3b4582df 100644 --- a/city_model_structure/city.py +++ b/city_model_structure/city.py @@ -60,15 +60,12 @@ class City: return None def add_city_object(self, new_city_object): - print('add city object') if self._city_objects is None: self._city_objects = [] for city_object in self.city_objects: - # ToDo: Check for shared walls. for surface in city_object.surfaces: for surface2 in new_city_object.surfaces: surface.shared(surface2) - print('added city object') self._city_objects.append(new_city_object) @property diff --git a/city_model_structure/material.py b/city_model_structure/material.py index 2473c9ad..9a247003 100644 --- a/city_model_structure/material.py +++ b/city_model_structure/material.py @@ -1,6 +1,5 @@ class Material: def __init__(self): - # ToDo: construct this class self._conductivity_wm_k = None self._specific_heat_jkg_k = None self._density_kg_m3 = None diff --git a/city_model_structure/surface.py b/city_model_structure/surface.py index b431caad..675c417d 100644 --- a/city_model_structure/surface.py +++ b/city_model_structure/surface.py @@ -28,13 +28,13 @@ class Surface: self._parent = None self._shapely = None self._projected_surface = None - self._lower_corner = None self._min_x = None self._min_y = None self._min_z = None self._shared_surfaces = [] self._global_irradiance_hour = np.zeros(8760) self._global_irradiance_month = np.zeros(12) + self._ground_coordinates = (self.min_x, self.min_y, self.min_z) def parent(self, parent, surface_id): self._parent = parent @@ -55,7 +55,7 @@ class Surface: self._swr = value @property - def points(self): + def points(self) -> np.ndarray: if self._points is None: self._points = np.fromstring(self._coordinates, dtype=float, sep=' ') self._points = Geometry.to_points_matrix(self._points, self._remove_last) @@ -95,13 +95,13 @@ class Surface: return self._min_z @property - def ground_points(self): + def ground_points(self) -> np.ndarray: if self._ground_points is None: coordinates = '' for point in self.points: - x = point[0] - self._lower_corner[0] - y = point[1] - self._lower_corner[1] - z = point[2] - self._lower_corner[2] + x = point[0] - self._ground_coordinates[0] + y = point[1] - self._ground_coordinates[1] + z = point[2] - self._ground_coordinates[2] if coordinates != '': coordinates = coordinates + ' ' coordinates = coordinates + str(x) + ' ' + str(y) + ' ' + str(z) @@ -110,14 +110,14 @@ class Surface: return self._ground_points @property - def points_list(self): + def points_list(self) -> np.ndarray: if self._points_list is None: s = self.points self._points_list = np.reshape(s, len(s) * 3) return self._points_list @property - def polygon(self): + def polygon(self) -> pn.Polygon: if self._polygon is None: try: self._polygon = pn.Polygon(self.points) @@ -127,7 +127,7 @@ class Surface: return self._polygon @property - def ground_polygon(self): + def ground_polygon(self) -> Union[pn.Polygon, None]: if self._ground_polygon is None: try: self._ground_polygon = pn.Polygon(self.ground_points) @@ -172,7 +172,7 @@ class Surface: return self._area_below_ground @property - def normal(self): + def normal(self) -> np.ndarray: if self._normal is None: points = self.points n = np.cross(points[1] - points[0], points[2] - points[0]) @@ -217,7 +217,6 @@ class Surface: self._shared_surfaces.append((percent, surface)) surface.add_shared(self, intersection_area) - @property def global_irradiance_hour(self): return self._global_irradiance_hour @@ -263,8 +262,8 @@ class Surface: min_x = min(self.min_x, surface.min_x) min_y = min(self.min_y, surface.min_y) min_z = min(self.min_z, surface.min_z) - self._lower_corner = (min_x, min_y, min_z) - surface._lower_corner = (min_x, min_y, min_z) + self._ground_coordinates = (min_x, min_y, min_z) + surface._ground_coordinates = (min_x, min_y, min_z) origin = (0, 0, 0) azimuth = self.azimuth - (np.pi / 2) while azimuth < 0: diff --git a/city_model_structure/thermal_zone.py b/city_model_structure/thermal_zone.py index c9749db0..b9efbc30 100644 --- a/city_model_structure/thermal_zone.py +++ b/city_model_structure/thermal_zone.py @@ -1,5 +1,6 @@ from typing import List from city_model_structure.thermal_boundary import ThermalBoundary +from city_model_structure.usage_zone import UsageZone class ThermalZone: @@ -86,10 +87,9 @@ class ThermalZone: self._infiltration_rate_system_off = value @property - def usage_zones(self): + def usage_zones(self) -> List[UsageZone]: return self._usage_zones @usage_zones.setter def usage_zones(self, values): self._usage_zones = values - diff --git a/city_model_structure/window.py b/city_model_structure/window.py index 271a1aa9..36085538 100644 --- a/city_model_structure/window.py +++ b/city_model_structure/window.py @@ -1,6 +1,5 @@ class Window: def __init__(self): - # ToDo: construct this class self._conductivity_wm_k = None self._solar_transmittance_at_normal_incidence = None self._front_side_solar_reflectance_at_normal_incidence = None diff --git a/physics/physics_factory.py b/physics/physics_factory.py index 7ac3a327..af7c89ea 100644 --- a/physics/physics_factory.py +++ b/physics/physics_factory.py @@ -3,16 +3,17 @@ from physics.physics_feeders.us_physics_parameters import UsPhysicsParameters class PhysicsFactory: - def __init__(self, handler, city): + def __init__(self, handler, city, base_path='data/physics'): self._handler = handler.lower().replace(' ', '_') self._city = city + self._base_path = base_path self.factory() def us_new_york_city(self): - UsNewYorkCityPhysicsParameters(self._city) + UsNewYorkCityPhysicsParameters(self._city, self._base_path) def us(self): - UsPhysicsParameters(self._city) + UsPhysicsParameters(self._city, self._base_path) def ca(self): raise Exception('Not implemented') diff --git a/physics/physics_feeders/us_base_physics_parameters.py b/physics/physics_feeders/us_base_physics_parameters.py index bfd00443..b261e4f4 100644 --- a/physics/physics_feeders/us_base_physics_parameters.py +++ b/physics/physics_feeders/us_base_physics_parameters.py @@ -6,17 +6,17 @@ from physics.physics_feeders.helpers.us_to_library_types import UsToLibraryTypes class UsBasePhysicsParameters: - def __init__(self, climate_zone, city_objects, function_to_type): + def __init__(self, climate_zone, city_objects, function_to_type, base_path): self._climate_zone = climate_zone self._city_objects = city_objects # load US Library - path = str(Path.cwd() / 'data/physics/us_constructions.xml') + path = str(Path.cwd() / base_path / 'us_constructions.xml') with open(path) as xml: self._library = xmltodict.parse(xml.read(), force_list='layer') # load US Archetypes - path = str(Path.cwd() / 'data/physics/us_archetypes.xml') + path = str(Path.cwd() / base_path / 'us_archetypes.xml') with open(path) as xml: self._archetypes = xmltodict.parse(xml.read(), force_list='layer') for city_object in self._city_objects: diff --git a/physics/physics_feeders/us_new_york_city_physics_parameters.py b/physics/physics_feeders/us_new_york_city_physics_parameters.py index 67b667ff..9bb5549d 100644 --- a/physics/physics_feeders/us_new_york_city_physics_parameters.py +++ b/physics/physics_feeders/us_new_york_city_physics_parameters.py @@ -3,7 +3,7 @@ from physics.physics_feeders.helpers.us_pluto_to_function import UsPlutoToFuncti class UsNewYorkCityPhysicsParameters(UsBasePhysicsParameters): - def __init__(self, city): + def __init__(self, city, base_path): self._city = city climate_zone = 'ASHRAE_2004:4A' - super().__init__(climate_zone, self._city.city_objects, Pf.function) + super().__init__(climate_zone, self._city.city_objects, Pf.function, base_path) diff --git a/physics/physics_feeders/us_physics_parameters.py b/physics/physics_feeders/us_physics_parameters.py index 34202f0e..930bc879 100644 --- a/physics/physics_feeders/us_physics_parameters.py +++ b/physics/physics_feeders/us_physics_parameters.py @@ -3,8 +3,8 @@ from physics.physics_feeders.helpers.us_to_library_types import UsToLibraryTypes class UsPhysicsParameters(UsBasePhysicsParameters): - def __init__(self, city): + def __init__(self, city, base_path): self._city = city self._climate_zone = UsToLibraryTypes.city_to_climate_zone(city.name) - super().__init__(self._climate_zone, self._city.city_objects, lambda function: function) + super().__init__(self._climate_zone, self._city.city_objects, lambda function: function, base_path) diff --git a/tests/test_geometry_factory.py b/tests/test_geometry_factory.py index 4633c6ea..bbd36ac4 100644 --- a/tests/test_geometry_factory.py +++ b/tests/test_geometry_factory.py @@ -1,6 +1,7 @@ from unittest import TestCase from pathlib import Path from geometry.geometry_factory import GeometryFactory +import os from city_model_structure.surface import Surface @@ -25,6 +26,8 @@ class TestGeometryFactory(TestCase): self.assertIsNotNone(city.lower_corner, 'lower_corner is none') self.assertIsNotNone(city.upper_corner, 'upper_corner is none') self.assertIsNotNone(city.name, 'name is none') + self.assertIsNotNone(city.country_code, 'country code is none') + self.assertIsNotNone(city.location, 'location is none') def test_citygml_city_objects(self): city = self.get_citygml() @@ -35,6 +38,7 @@ class TestGeometryFactory(TestCase): self.assertIsNotNone(city_object.function, 'city_object function is none') self.assertIsNotNone(city_object.volume, 'city_object volume is none') self.assertIsNotNone(city_object.surfaces, 'city_object surfaces is none') + self.assertIsNotNone(city_object.surfaces[0].name, 'surface not found') self.assertIsNotNone(city_object.basement_heated, 'city_object basement_heated is none') self.assertIsNotNone(city_object.attic_heated, 'city_object attic_heated is none') self.assertIsNotNone(city_object.terrains, 'city_object terrains is none') @@ -42,6 +46,12 @@ class TestGeometryFactory(TestCase): self.assertIsNotNone(city_object.usage_zones, 'city_object usage_zones is none') self.assertIsNone(city_object.average_storey_height, 'city_object average_storey_height is not none') self.assertIsNone(city_object.storeys_above_ground, 'city_object storeys_above_ground is not none') + self.assertIsNotNone(city_object.heated_volume, 'city_object heated_volume is none') + self.assertIsNotNone(city_object.thermal_zones, 'city_object thermal_zones is none') + self.assertIsNotNone(city_object.type, 'city_object type is none') + self.assertIsNotNone(city_object.max_height, 'city_object max_height is none') + city_object.stl_export(self._example_path) + os.remove(Path(self._example_path, city_object.name + '.stl').resolve()) def test_citygml_surfaces(self): city = self.get_citygml() @@ -63,6 +73,12 @@ class TestGeometryFactory(TestCase): self.assertIsNotNone(surface.normal, 'surface normal is none') self.assertIsNotNone(surface.projection, 'surface projection is none') self.assertIsNotNone(surface.swr, 'surface swr is none') + self.assertIsNotNone(surface.min_x, 'surface min_x is none') + self.assertIsNotNone(surface.min_y, 'surface min_y is none') + self.assertIsNotNone(surface.min_z, 'surface min_z is none') + self.assertIsNotNone(surface.ground_polygon, 'surface ground_polygon is none') + self.assertIsNotNone(surface.ground_points, 'surface ground_points is none') + self.assertIsNotNone(surface.intersect(surface), 'self intersection is none') def test_citygml_thermal_zone(self): city = self.get_citygml() @@ -83,6 +99,8 @@ class TestGeometryFactory(TestCase): 'thermal_zone infiltration_rate_system_off is not none') self.assertIsNone(thermal_zone.infiltration_rate_system_on, 'thermal_zone infiltration_rate_system_on is not none') + self.assertIsNone(thermal_zone.usage_zones, + 'thermal_zone usage_zones are not none') def test_citygml_thermal_boundary(self): city = self.get_citygml() @@ -102,8 +120,6 @@ class TestGeometryFactory(TestCase): 'thermal_boundary outside_solar_absorptance was initialized') self.assertIsNone(thermal_boundary.outside_thermal_absorptance, 'thermal_boundary outside_thermal_absorptance was initialized') - self.assertIsNone(thermal_boundary.outside_thermal_absorptance, - 'thermal_boundary outside_thermal_absorptance was initialized') self.assertIsNone(thermal_boundary.outside_visible_absorptance, 'thermal_boundary outside_visible_absorptance was initialized') self.assertRaises(Exception, lambda: thermal_boundary.shortwave_reflectance, @@ -129,20 +145,3 @@ class TestGeometryFactory(TestCase): 'thermal_opening outside_reflectance was initialized') self.assertIsNone(thermal_opening.thickness_m, 'thermal_opening thickness_m was initialized') self.assertRaises(Exception, lambda: thermal_opening.u_value, 'thermal_opening u_value was initialized') - - def test_rotation(self): - s = Surface('-4.330008674901071 -2.2499999999999982 0.0 0.12097547700892843 -2.2499999999999982 0.0 0.12097547700892843 -2.25 0.0 -4.330008674901074 -2.2499999999999996 0.0', remove_last=False) - print(s.inclination) - print(s.polygon) - surface3 = Surface('0 0 0 0 0 3 3 0 3 3 0 0 0 0 0') - surface4 = Surface('0 0 0 0 1 3 3 1 3 3 0 0 0 0 0') - - - surface4.intersect(surface3) - ''' - surface1 = Surface('301104.7614957978 56642.02970768605 9.0 301097.510030954 56646.7245319048 0.0 301091.984640329 56650.30216862355 9.0 301104.7614957978 56642.02970768605 9.0') - surface2 = Surface('301070.5715543915 56635.9657428423 0.0 301070.863546579 56617.6366412798 0.0 301067.7356168915 56631.5018756548 0.0 301070.5715543915 56635.9657428423 0.0') - surface1.intersect(surface2) - surface2.intersect(surface1) - ''' - diff --git a/tests/test_physics_factory.py b/tests/test_physics_factory.py index 0baf5d52..889d6690 100644 --- a/tests/test_physics_factory.py +++ b/tests/test_physics_factory.py @@ -1,7 +1,27 @@ from unittest import TestCase +from pathlib import Path +from geometry.geometry_factory import GeometryFactory +from physics.physics_factory import PhysicsFactory class TestPhysicsFactory(TestCase): - def test_us_new_york_city(self): - self.assertTrue(True) + def setUp(self) -> None: + self._city_gml = None + self._nyc_with_physics = None + self._example_path = (Path(__file__).parent.parent / 'tests_data').resolve() + def get_citygml(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') + return self._city_gml + + def get_city_with_physics(self): + if self._nyc_with_physics is None: + self._nyc_with_physics = self.get_citygml() + PhysicsFactory('us_new_york_city', self._nyc_with_physics, base_path=self._example_path) + return self._nyc_with_physics + + def test_city_with_physics(self): + city = self.get_city_with_physics() \ No newline at end of file diff --git a/tests_data/us_archetypes.xml b/tests_data/us_archetypes.xml new file mode 100644 index 00000000..bbe49e54 --- /dev/null +++ b/tests_data/us_archetypes.xml @@ -0,0 +1,786 @@ + + + + + + 0.21 + 4 + + + 0 + + + + 0 + + + + 3.05 + 2 + 130 + 0.15 + 0.15 + 0.5 + 0 + + + + + 0.33 + 4 + + + 0 + + + + 0 + + + + 3.34 + 3 + 90 + 0.15 + 0.15 + 0.50 + 0 + + + + + 0.38 + 4 + + + 0 + + + + 0 + + + + 3.34 + 3 + 130 + 0.15 + 0.15 + 0.50 + 0 + + + + + 0.35 + 4 + + + 0 + + + + 0.0019 + 2 + + + 3.96 + 3 + 90 + 0.15 + 0.15 + 0.50 + 0 + + + + + 0.33 + 4 + + + 0 + + + + 0.0068 + 2 + + + 3.96 + 3 + 90 + 0.15 + 0.15 + 0.50 + 0 + + + + + 0.07 + 4 + + + 0 + + + + 0.0064 + 2 + + + 6.1 + 3 + 130 + 0.15 + 0.15 + 0.50 + 0 + + + + + 0.11 + 4 + + + 0 + + + + 0 + + + + 5.18 + 3 + 90 + 0.15 + 0.15 + 0.50 + 0 + + + + + 0.11 + 4 + + + 0 + + + + 0 + + + + 6.1 + 1 + 130 + 0.15 + 0.15 + 0.50 + 0 + + + + + 0.14 + 4 + + + 0 + + + + 0 + + + + 3.05 + 3 + 90 + 0.15 + 0.15 + 0.50 + 0 + + + + + 0.17 + 4 + + + 0 + + + + 0 + + + + 3.05 + 3 + 90 + 0.15 + 0.15 + 0.50 + 0 + + + + + 0.11 + 4 + + + 0 + + + + 0 + + + + 3.05 + 3 + 90 + 0.15 + 0.15 + 0.50 + 0 + + + + + 0.3 + 4 + + + 0 + + + + 0 + + + + 3.05 + 3 + 130 + 0.15 + 0.15 + 0.50 + 0 + + + + + 0.15 + 4 + + + 0 + + + + 0 + + + + 4.27 + 3 + 130 + 0.15 + 0.15 + 0.50 + 0 + + + + + 0.2 + 4 + + + 0 + + + + 0 + + + + 3.05 + 3 + 90 + 0.15 + 0.15 + 0.50 + 0 + + + + + 0.006 + 4 + + + 0 + + + + .0032 + 2 + + + 8.53 + 3 + 90 + 0.15 + 0.15 + 0.50 + 0 + + + + + 0.15 + 4 + + + 0 + + + + 0 + + + + 3.05 + 3 + 90 + 0.15 + 0.15 + 0.50 + 0 + + + + + 0.3 + 4 + + + 0 + + + + 0 + + + + 3.05 + 3 + 90 + 0.15 + 0.15 + 0.50 + 0 + + + + + 0.21 + 3 + + + 0 + + + + 0 + + + + 3.05 + 2 + 130 + 0.05 + 0.15 + 0.1 + 0 + + + + + 0.33 + 3 + + + 0 + + + + 0 + + + + 3.34 + 3 + 90 + 0.05 + 0.15 + 0.1 + 0 + + + + + 0.38 + 3 + + + 0 + + + + 0 + + + + 3.34 + 3 + 130 + 0.05 + 0.15 + 0.1 + 0 + + + + + 0.35 + 3 + + + 0 + + + + 0.0019 + 1 + + + 3.96 + 3 + 90 + 0.05 + 0.15 + 0.1 + 0 + + + + + 0.33 + 3 + + + 0 + + + + 0.0068 + 1 + + + 3.96 + 3 + 90 + 0.05 + 0.15 + 0.1 + 0 + + + + + 0.07 + 3 + + + 0 + + + + 0.0064 + 1 + + + 6.1 + 3 + 130 + 0.05 + 0.15 + 0.1 + 0 + + + + + 0.11 + 3 + + + 0 + + + + 0 + + + + 5.18 + 3 + 90 + 0.05 + 0.15 + 0.1 + 0 + + + + + 0.11 + 3 + + + 0 + + + + 0 + + + + 6.1 + 1 + 130 + 0.05 + 0.15 + 0.10 + 0 + + + + + 0.14 + 3 + + + 0 + + + + 0 + + + + 3.05 + 3 + 90 + 0.05 + 0.15 + 0.10 + 0 + + + + + 0.17 + 3 + + + 0 + + + + 0 + + + + 3.05 + 3 + 90 + 0.05 + 0.15 + 0.10 + 0 + + + + + 0.11 + 3 + + + 0 + + + + 0 + + + + 3.05 + 3 + 90 + 0.05 + 0.15 + 0.10 + 0 + + + + + 0.3 + 3 + + + 0 + + + + 0 + + + + 3.05 + 3 + 130 + 0.05 + 0.15 + 0.10 + 0 + + + + + 0.15 + 3 + + + 0 + + + + 0 + + + + 4.27 + 3 + 130 + 0.05 + 0.15 + 0.10 + 0 + + + + + 0.2 + 3 + + + 0 + + + + 0 + + + + 3.05 + 3 + 90 + 0.05 + 0.15 + 0.10 + 0 + + + + + 0.006 + 3 + + + 0 + + + + .0032 + 1 + + + 8.53 + 3 + 90 + 0.05 + 0.15 + 0.10 + 0 + + + + + 0.15 + 3 + + + 0 + + + + 0 + + + + 3.05 + 3 + 90 + 0.05 + 0.15 + 0.10 + 0 + + + + + 0.3 + 3 + + + 0 + + + + 0 + + + + 3.05 + 3 + 90 + 0.05 + 0.15 + 0.10 + 0 + + + diff --git a/tests_data/us_constructions.xml b/tests_data/us_constructions.xml new file mode 100644 index 00000000..c18ec613 --- /dev/null +++ b/tests_data/us_constructions.xml @@ -0,0 +1,606 @@ + + + + + 0.32 + 0 + 0.003 + 0.301483 + 0.648517 + 0.648517 + 0.0133144 + + + 0.49 + 0 + 0.003 + 0.481761 + 0.468239 + 0.468239 + 0.03026 + + + 0.35 + 0 + 0.003 + 0.328881 + 0.621119 + 0.621119 + 0.0071399 + + + 0.36 + 0 + 0.003 + 0.354957 + 0.595043 + 0.595043 + 0.0134755 + + + + + 1.311 + 2240 + 836.8 + 0.9 + 0.7 + 0.7 + + + true + 0.21648 + 0.9 + 0.7 + 0.8 + + + 0.045 + 265 + 836.8 + 0.9 + 0.7 + 0.7 + + + 0.6918 + 1858 + 837 + 0.9 + 0.92 + 0.92 + + + 1.7296 + 2243 + 837 + 0.9 + 0.65 + 0.65 + + + 0.0432 + 91 + 837 + 0.9 + 0.5 + 0.5 + + + 0.16 + 784.9 + 830 + 0.9 + 0.92 + 0.92 + + + 0.11 + 544.62 + 1210 + 0.9 + 0.78 + 0.78 + + + 0.115 + 513 + 1255 + 0.9 + 0.78 + 0.78 + + + 0.1211 + 593 + 2510 + 0.9 + 0.78 + 0.78 + + + 0.049 + 265 + 836.8 + 0.9 + 0.7 + 0.7 + + + true + 0.36256 + 0.9 + 0.7 + 0.7 + + + true + 0.36256 + 0.9 + 0.7 + 0.7 + + + 45.006 + 7680 + 418.4 + 0.9 + 0.7 + 0.3 + + + 0.16 + 1121.29 + 1460 + 0.9 + 0.7 + 0.7 + + + true + 0.21648 + 0.9 + 0.7 + 0.8 + + + true + 0.36256 + 0.9 + 0.7 + 0.7 + + + true + 0.21648 + 0.9 + 0.7 + 0.8 + + + true + 0.36256 + 0.9 + 0.7 + 0.7 + + + true + 0.21648 + 0.9 + 0.7 + 0.8 + + + 0.045 + 265 + 836.8 + 0.9 + 0.7 + 0.7 + + + 44.96 + 7688.86 + 410 + 0.9 + 0.2 + 0.2 + + + + + + + + 3 + 0.0795397 + + + 1 + 0.20321 + + + 2 + + + + + 0.92 + 0.9 + 0.92 + + + 4 + 0.0253 + + + 5 + 0.2033 + + + 6 + 0.0680962 + + + 7 + 0.01271 + + + + + 0.92 + 0.9 + 0.92 + + + 8 + 0.01 + + + 3 + 0.0746874 + + + 7 + 0.01271 + + + + + 0.78 + 0.9 + 0.78 + + + 9 + 0.0178 + + + 10 + 0.0254 + + + 11 + 0.375211 + + + 7 + 0.01271 + + + + + 0.78 + 0.9 + 0.78 + + + 9 + 0.0178 + + + 10 + 0.0254 + + + 11 + 0.221604 + + + 7 + 0.01271 + + + + + 0.92 + 0.9 + 0.92 + + + 12 + + + 3 + 0.118387 + + + 7 + 0.01271 + + + + + + + 1 + 0.20321 + + + + + 0.92 + 0.9 + 0.92 + + + 13 + + + 3 + 0.0373223 + + + 7 + 0.01271 + + + + + 0.7 + 0.9 + 0.7 + + + 15 + 0.0095 + + + 11 + 0.210538 + + + 14 + 0.001524 + + + + + + + 1 + 0.1016 + + + + + 0.7 + 0.9 + 0.3 + + + 14 + 0.001524 + + + 11 + 0.23578 + + + + + + + 1 + 0.1016 + + + 16 + + + + + 0.92 + 0.9 + 0.92 + + + 4 + 0.0253 + + + 5 + 0.2033 + + + 6 + 0.0338606 + + + 7 + 0.01271 + + + + + 0.7 + 0.9 + 0.3 + + + 14 + 0.001524 + + + 11 + 0.123533 + + + + + 0.92 + 0.9 + 0.92 + + + 17 + + + 3 + 0.118387 + + + 7 + 0.01271 + + + + + 0.92 + 0.9 + 0.92 + + + 8 + 0.01 + + + 3 + 0.110422 + + + 7 + 0.01271 + + + + + 0.7 + 0.9 + 0.7 + + + 15 + 0.0095 + + + 11 + 0.124958 + + + 14 + 0.001524 + + + + + + + 3 + 0.0463846 + + + 1 + 0.20321 + + + 18 + + + + + 0.92 + 0.9 + 0.92 + + + 19 + + + 3 + 0.0971136 + + + 7 + 0.01271 + + + + + + + 1 + 0.20321 + + + + + + + 1 + 0.1016 + + + + + + + 1 + 0.1016 + + + 20 + + + + + 0.92 + 0.9 + 0.92 + + + 22 + 0.0015 + + + 21 + 0.139618 + + + 7 + 0.01271 + + + + + 0.92 + 0.9 + 0.92 + + + 22 + 0.0015 + + + 21 + 0.0598725 + + + 7 + 0.01271 + + + + + \ No newline at end of file