eliminated many parameters from configuration.ini that will now depend on the workflow

added example iso 52016-1:2017
added new weather format defined in iso 52016-1:2017 (xls)
This commit is contained in:
Pilar 2021-01-11 17:11:50 -05:00
parent 215d62b62b
commit e9dd9c2221
16 changed files with 253 additions and 151 deletions

View File

@ -8,7 +8,6 @@ from typing import List
from city_model_structure.attributes.layer import Layer from city_model_structure.attributes.layer import Layer
from city_model_structure.attributes.thermal_opening import ThermalOpening from city_model_structure.attributes.thermal_opening import ThermalOpening
from city_model_structure.attributes.thermal_zone import ThermalZone from city_model_structure.attributes.thermal_zone import ThermalZone
from helpers.configuration_helper import ConfigurationHelper
from city_model_structure.attributes.surface import Surface from city_model_structure.attributes.surface import Surface
@ -16,20 +15,22 @@ class ThermalBoundary:
""" """
ThermalBoundary class ThermalBoundary class
""" """
def __init__(self, surface, delimits): def __init__(self, surface, delimits, hi, he):
self._surface = surface self._surface = surface
self._delimits = delimits self._delimits = delimits
# ToDo: up to at least LOD2 will be just one thermal opening per Thermal boundary, review for LOD3 and LOD4 # ToDo: up to at least LOD2 will be just one thermal opening per Thermal boundary, review for LOD3 and LOD4
self._thermal_openings = [ThermalOpening()] self._thermal_openings = [ThermalOpening(hi, he)]
self._layers = None self._layers = None
self._outside_solar_absorptance = ConfigurationHelper().outside_solar_absorptance self._outside_solar_absorptance = None
self._outside_thermal_absorptance = None self._outside_thermal_absorptance = None
self._outside_visible_absorptance = None self._outside_visible_absorptance = None
self._window_ratio = None self._window_ratio = None
self._u_value = None self._u_value = None
self._window_area = None self._window_area = None
self._shortwave_reflectance = 1 - self._outside_solar_absorptance self._shortwave_reflectance = None
self._construction_name = None self._construction_name = None
self._hi = hi
self._he = he
@property @property
def surface(self) -> Surface: def surface(self) -> Surface:
@ -232,8 +233,8 @@ class ThermalBoundary:
:return: float :return: float
""" """
if self._u_value is None: if self._u_value is None:
h_i = ConfigurationHelper().h_i h_i = self._hi
h_e = ConfigurationHelper().h_e h_e = self._he
r_value = 1.0/h_i + 1.0/h_e r_value = 1.0/h_i + 1.0/h_e
try: try:
for layer in self.layers: for layer in self.layers:

View File

@ -4,22 +4,23 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
Contributors Pilar Monsalvete pilar_monsalvete@yahoo.es Contributors Pilar Monsalvete pilar_monsalvete@yahoo.es
""" """
from helpers.configuration_helper import ConfigurationHelper
class ThermalOpening: class ThermalOpening:
""" """
ThermalOpening class ThermalOpening class
""" """
def __init__(self): def __init__(self, hi, he):
self._openable_ratio = None self._openable_ratio = None
self._conductivity = None self._conductivity = None
self._frame_ratio = ConfigurationHelper().frame_ratio self._frame_ratio = 0
self._g_value = None self._g_value = None
self._thickness = None self._thickness = None
self._front_side_solar_transmittance_at_normal_incidence = None self._front_side_solar_transmittance_at_normal_incidence = None
self._back_side_solar_transmittance_at_normal_incidence = None self._back_side_solar_transmittance_at_normal_incidence = None
self._overall_u_value = None self._overall_u_value = None
self._hi = hi
self._he = he
@property @property
def openable_ratio(self): def openable_ratio(self):
@ -57,8 +58,8 @@ class ThermalOpening:
# This ensures a more robust code that returns the overall_u_value regardless the order the parameters are read. # This ensures a more robust code that returns the overall_u_value regardless the order the parameters are read.
self._conductivity = value self._conductivity = value
if self._overall_u_value is None and self.thickness is not None: if self._overall_u_value is None and self.thickness is not None:
h_i = ConfigurationHelper().h_i h_i = self._hi
h_e = ConfigurationHelper().h_e h_e = self._he
r_value = 1 / h_i + 1 / h_e + float(self.conductivity) / float(self.thickness) r_value = 1 / h_i + 1 / h_e + float(self.conductivity) / float(self.thickness)
self._overall_u_value = 1 / r_value self._overall_u_value = 1 / r_value
@ -115,8 +116,8 @@ class ThermalOpening:
# This ensures a more robust code that returns the overall_u_value regardless the order the parameters are read. # This ensures a more robust code that returns the overall_u_value regardless the order the parameters are read.
self._thickness = value self._thickness = value
if self._overall_u_value is None and self.conductivity is not None: if self._overall_u_value is None and self.conductivity is not None:
h_i = ConfigurationHelper().h_i h_i = self._hi
h_e = ConfigurationHelper().h_e h_e = self._he
r_value = 1 / h_i + 1 / h_e + float(self.conductivity) / float(self.thickness) r_value = 1 / h_i + 1 / h_e + float(self.conductivity) / float(self.thickness)
self._overall_u_value = 1 / r_value self._overall_u_value = 1 / r_value

View File

@ -7,7 +7,6 @@ from typing import List, TypeVar
from city_model_structure.attributes.surface import Surface from city_model_structure.attributes.surface import Surface
from city_model_structure.attributes.usage_zone import UsageZone from city_model_structure.attributes.usage_zone import UsageZone
from helpers.configuration_helper import ConfigurationHelper
ThermalBoundary = TypeVar('ThermalBoundary') ThermalBoundary = TypeVar('ThermalBoundary')
@ -16,16 +15,16 @@ class ThermalZone:
""" """
ThermalZone class ThermalZone class
""" """
def __init__(self, surfaces): def __init__(self, surfaces, heated, cooled):
self._surfaces = surfaces self._surfaces = surfaces
self._floor_area = None self._floor_area = None
self._bounded = None self._bounded = None
self._heated = ConfigurationHelper().heated self._heated = heated
self._cooled = ConfigurationHelper().cooled self._cooled = cooled
self._additional_thermal_bridge_u_value = ConfigurationHelper().additional_thermal_bridge_u_value self._additional_thermal_bridge_u_value = 0
self._effective_thermal_capacity = None self._effective_thermal_capacity = None
self._indirectly_heated_area_ratio = ConfigurationHelper().indirectly_heated_area_ratio self._indirectly_heated_area_ratio = 0
self._infiltration_rate_system_on = ConfigurationHelper().infiltration_rate_system_on self._infiltration_rate_system_on = 0
self._infiltration_rate_system_off = None self._infiltration_rate_system_off = None
self._usage_zones = None self._usage_zones = None

View File

@ -6,7 +6,6 @@ Contributors Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
""" """
from typing import List from typing import List
from city_model_structure.attributes.internal_gains import InternalGains from city_model_structure.attributes.internal_gains import InternalGains
from helpers.configuration_helper import ConfigurationHelper
from city_model_structure.attributes.lighting import Lighting from city_model_structure.attributes.lighting import Lighting
@ -14,7 +13,7 @@ class UsageZone:
""" """
UsageZone class UsageZone class
""" """
def __init__(self): def __init__(self, min_air_change):
self._usage = None self._usage = None
self._internal_gains = None self._internal_gains = None
self._heating_setpoint = None self._heating_setpoint = None
@ -28,7 +27,7 @@ class UsageZone:
self._electrical_app_average_consumption_sqm_year = None self._electrical_app_average_consumption_sqm_year = None
# todo: mechanical_air_change must come from library, talk to Rabeeh # todo: mechanical_air_change must come from library, talk to Rabeeh
# todo: check to clean code and un-used attributes # todo: check to clean code and un-used attributes
self._mechanical_air_change = ConfigurationHelper().min_air_change self._mechanical_air_change = min_air_change
self._occupancy = None self._occupancy = None
self._schedules = None self._schedules = None
self._heating_schedule = None self._heating_schedule = None

View File

@ -25,8 +25,8 @@ class Building(CityObject):
""" """
Building(CityObject) class Building(CityObject) class
""" """
def __init__(self, name, lod, surfaces, terrains, year_of_construction, function, lower_corner, attic_heated=0, def __init__(self, name, lod, surfaces, terrains, year_of_construction, function, lower_corner, heated=True,
basement_heated=0): cooled=True, hi=10, he=25, attic_heated=0, basement_heated=0):
super().__init__(lod, surfaces, name) super().__init__(lod, surfaces, name)
self._basement_heated = basement_heated self._basement_heated = basement_heated
self._attic_heated = attic_heated self._attic_heated = attic_heated
@ -34,6 +34,10 @@ class Building(CityObject):
self._year_of_construction = year_of_construction self._year_of_construction = year_of_construction
self._function = function self._function = function
self._lower_corner = lower_corner self._lower_corner = lower_corner
self._heated = heated
self._cooled = cooled
self._hi = hi
self._he = he
self._average_storey_height = None self._average_storey_height = None
self._storeys_above_ground = None self._storeys_above_ground = None
self._foot_print = None self._foot_print = None
@ -51,10 +55,10 @@ class Building(CityObject):
self._thermal_zones = [] self._thermal_zones = []
if self.lod < 8: if self.lod < 8:
# for lod under 4 is just one thermal zone # for lod under 4 is just one thermal zone
self._thermal_zones.append(ThermalZone(self.surfaces)) self._thermal_zones.append(ThermalZone(self.surfaces, self._heated, self._cooled))
for t_zones in self._thermal_zones: for t_zones in self._thermal_zones:
t_zones.bounded = [ThermalBoundary(s, [t_zones]) for s in t_zones.surfaces] t_zones.bounded = [ThermalBoundary(s, [t_zones], hi, he) for s in t_zones.surfaces]
surface_id = 0 surface_id = 0
for surface in self._surfaces: for surface in self._surfaces:
surface.lower_corner = self._lower_corner surface.lower_corner = self._lower_corner

View File

@ -1,23 +1,4 @@
# These values are intended as configurable assumptions # These values are intended as configurable assumptions
[convective_fluxes]
# interior convective coefficient in W/m2K
h_i = 10
# exterior convective coefficient in W/m2K
h_e = 25
[windows]
frame_ratio = 0
[thermal_zones]
heated = true
cooled = true
additional_thermal_bridge_u_value = 0
indirectly_heated_area_ratio = 0
infiltration_rate_system_on = 0
outside_solar_absorptance = 0.2
shortwave_reflectance = 0.8
min_air_change = 0.5
[buildings] [buildings]
max_location_distance_for_shared_walls = 100.0 max_location_distance_for_shared_walls = 5.0
min_coordinate = -1.7976931348623157e+308 min_coordinate = -1.7976931348623157e+308

View File

@ -16,6 +16,9 @@ class CaUsageParameters(HftUsageInterface):
def __init__(self, city, base_path): def __init__(self, city, base_path):
super().__init__(base_path, 'ca_archetypes_reduced.xml') super().__init__(base_path, 'ca_archetypes_reduced.xml')
self._city = city self._city = city
# todo: this is a wrong location for self._min_air_change -> re-think where to place this info
# and where it comes from
self._min_air_change = 0
def enrich_buildings(self): def enrich_buildings(self):
""" """
@ -32,7 +35,7 @@ class CaUsageParameters(HftUsageInterface):
mix_usage = False mix_usage = False
if not mix_usage: if not mix_usage:
# just one usage_zone # just one usage_zone
usage_zone = UsageZone() usage_zone = UsageZone(self._min_air_change)
self._assign_values(usage_zone, archetype) self._assign_values(usage_zone, archetype)
building.usage_zones = [usage_zone] building.usage_zones = [usage_zone]

View File

@ -18,6 +18,9 @@ class UsNewYorkCityUsageParameters(HftUsageInterface):
def __init__(self, city, base_path): def __init__(self, city, base_path):
super().__init__(base_path, 'de_library.xml') super().__init__(base_path, 'de_library.xml')
self._city = city self._city = city
# todo: this is a wrong location for self._min_air_change -> re-think where to place this info
# and where it comes from
self._min_air_change = 0
def enrich_buildings(self): def enrich_buildings(self):
""" """
@ -35,7 +38,8 @@ class UsNewYorkCityUsageParameters(HftUsageInterface):
mix_usage = False mix_usage = False
if not mix_usage: if not mix_usage:
# just one usage_zone # just one usage_zone
usage_zone = UsageZone() min_air_change = self._min_air_change
usage_zone = UsageZone(min_air_change)
self._assign_values(usage_zone, archetype) self._assign_values(usage_zone, archetype)
building.usage_zones = [usage_zone] building.usage_zones = [usage_zone]

View File

@ -5,6 +5,7 @@ Copyright © 2020 Project Author Pilar Monsalvete pilar_monsalvete@yahoo.es
""" """
from pathlib import Path from pathlib import Path
from factories.weather_feeders.dat_weather_parameters import DatWeatherParameters from factories.weather_feeders.dat_weather_parameters import DatWeatherParameters
from factories.weather_feeders.xls_weather_parameters import XlsWeatherParameters
class WeatherFactory: class WeatherFactory:
@ -12,12 +13,11 @@ class WeatherFactory:
WeatherFactory class WeatherFactory class
""" """
# todo: modify full_path_weather to make it depending on "city" def __init__(self, handler, city, city_name, base_path=Path(Path(__file__).parent.parent / 'data/weather')):
def __init__(self, handler, city, base_path=Path(Path(__file__).parent.parent / 'data/weather')):
self._handler = '_' + handler.lower().replace(' ', '_') self._handler = '_' + handler.lower().replace(' ', '_')
self._city = city self._city = city
self._base_path = base_path self._base_path = base_path
self._city_name = 'new_york_city' self._city_name = city_name
self.factory() self.factory()
def _dat(self): def _dat(self):
@ -26,6 +26,10 @@ class WeatherFactory:
def _tmy(self): def _tmy(self):
raise Exception('Not implemented') raise Exception('Not implemented')
def _xls(self):
name = 'ISO_52016_1_BESTEST_ClimData_2016.08.24'
XlsWeatherParameters(self._city, self._base_path, name)
def factory(self): def factory(self):
""" """
Enrich the city with the usage information Enrich the city with the usage information

View File

@ -1,11 +1,12 @@
""" """
CliWeatherParameters class to extract weather parameters from a defined region in .dat format DatWeatherParameters class to extract weather parameters from a defined region in .dat format
SPDX - License - Identifier: LGPL - 3.0 - or -later SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Pilar Monsalvete pilar_monsalvete@yahoo.es Copyright © 2020 Project Author Pilar Monsalvete pilar_monsalvete@yahoo.es
""" """
import pandas as pd import pandas as pd
from pathlib import Path from pathlib import Path
import sys
class DatWeatherParameters: class DatWeatherParameters:
@ -19,10 +20,14 @@ class DatWeatherParameters:
file_name = 'inseldb_' + self._city_name + '.dat' file_name = 'inseldb_' + self._city_name + '.dat'
self._path = Path(path / file_name) self._path = Path(path / file_name)
# TODO: catch error if file does not exist
if self._weather_values is None: if self._weather_values is None:
try:
self._weather_values = pd.read_csv(self._path, sep='\s+', header=None, self._weather_values = pd.read_csv(self._path, sep='\s+', header=None,
names=['hour', 'global_horiz', 'temperature', 'diffuse', 'beam', 'empty']) names=['hour', 'global_horiz', 'temperature', 'diffuse', 'beam', 'empty'])
except ValueError:
sys.stderr.write(f'Error: weather file {self._path} not found\n')
sys.exit()
for building in self._city.buildings: for building in self._city.buildings:
new_value = pd.DataFrame(self._weather_values[['temperature']].to_numpy(), columns=['inseldb']) new_value = pd.DataFrame(self._weather_values[['temperature']].to_numpy(), columns=['inseldb'])
if 'hour' not in building.external_temperature: if 'hour' not in building.external_temperature:

View File

@ -0,0 +1,47 @@
"""
XlsWeatherParameters class to extract weather parameters from a defined region in .xls format
defined and used by the norm iso 52016-1:2017
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Pilar Monsalvete pilar_monsalvete@yahoo.es
"""
import pandas as pd
from pathlib import Path
import sys
class XlsWeatherParameters:
"""
XlsWeatherParameters class
"""
def __init__(self, city, path, name):
self._weather_values = None
self._city = city
self._file_name = name
file_name = self._file_name + '.xls'
self._path = Path(path / file_name)
if self._weather_values is None:
try:
self._weather_values = pd.read_excel(self._path, skiprows=4, nrows=9504,
names=['hours_calc', 'month', 'week', 'day_of_week', 'hours_of_day',
'temperature', 'I_sol_vertical_N', 'I_sol_vertical_E',
'I_sol_vertical_S', 'I_sol_vertical_W', 'I_sol_45_N', 'I_sol_45_S',
'void', 'global_horiz', 'wind_velocity', 'humidity'])
except ValueError:
sys.stderr.write(f'Error reading weather file {self._path}\n')
sys.exit()
for building in self._city.buildings:
new_value = pd.DataFrame(self._weather_values[['temperature']].to_numpy(), columns=['iso52016'])
if 'hour' not in building.external_temperature:
building.external_temperature['hour'] = new_value
else:
pd.concat([building.external_temperature['hour'], new_value], axis=1)
new_value = pd.DataFrame(self._weather_values[['global_horiz']].to_numpy(), columns=['iso52016'])
if 'hour' not in building.global_horizontal:
building.global_horizontal['hour'] = new_value
else:
pd.concat([building.global_horizontal['hour'], new_value], axis=1)

View File

@ -16,87 +16,6 @@ class ConfigurationHelper:
self._config = configparser.ConfigParser() self._config = configparser.ConfigParser()
self._config.read(config_file) self._config.read(config_file)
@property
def h_i(self):
"""
Configured internal convective coefficient in W/m2K
:return: float
"""
return self._config.getfloat('convective_fluxes', 'h_i')
@property
def h_e(self):
"""
Configured external convective coefficient in W/m2K
:return: float
"""
return self._config.getfloat('convective_fluxes', 'h_e')
@property
def frame_ratio(self):
"""
Configured frame ratio
:return: float
"""
return self._config.getfloat('windows', 'frame_ratio')
@property
def heated(self):
"""
Configured heated flag
:return: Boolean
"""
return self._config.getboolean('thermal_zones', 'heated')
@property
def cooled(self):
"""
Configured cooled flag
:return: Boolean
"""
return self._config.getboolean('thermal_zones', 'cooled')
@property
def additional_thermal_bridge_u_value(self):
"""
Configured additional thermal bridge u value W/m2K
:return:
"""
return self._config.getfloat('thermal_zones', 'additional_thermal_bridge_u_value')
@property
def indirectly_heated_area_ratio(self):
"""
Configured indirectly heated area ratio
:return: float
"""
return self._config.getfloat('thermal_zones', 'indirectly_heated_area_ratio')
@property
def infiltration_rate_system_on(self):
"""
Configured infiltration rate system on in air change per hour
:return: float
"""
return self._config.getfloat('thermal_zones', 'infiltration_rate_system_on')
@property
def outside_solar_absorptance(self):
"""
Configured exterior solar absorptance
:return: float
"""
return self._config.getfloat('thermal_zones', 'outside_solar_absorptance')
@property
def min_air_change(self):
"""
Configured minimum air change rate in air changes per hour
:return: float
"""
return self._config.getfloat('thermal_zones', 'min_air_change')
@property @property
def max_location_distance_for_shared_walls(self): def max_location_distance_for_shared_walls(self):
""" """

View File

@ -35,9 +35,7 @@ class GeometryHelper:
:return: Boolean :return: Boolean
""" """
max_distance = ConfigurationHelper().max_location_distance_for_shared_walls max_distance = ConfigurationHelper().max_location_distance_for_shared_walls
x = location1[0] - location2[0] return GeometryHelper.distance_between_points(location1, location2) < max_distance
y = location1[1] - location2[1]
return GeometryHelper.distance_between_points(x, y) < max_distance
def almost_same_area(self, a1, a2): def almost_same_area(self, a1, a2):
""" """
@ -58,9 +56,7 @@ class GeometryHelper:
:param v2: [x,y,z] :param v2: [x,y,z]
:return: Boolean :return: Boolean
""" """
print('3 dimensions')
delta = self.distance_between_points(v1, v2) delta = self.distance_between_points(v1, v2)
print('delta', delta)
return delta <= self._delta return delta <= self._delta
def is_almost_same_surface(self, s1, s2): def is_almost_same_surface(self, s1, s2):

View File

@ -5,7 +5,6 @@ Copyright © 2020 Project Author Pilar Monsalvete pilar_monsalvete@yahoo.es
""" """
from pathlib import Path from pathlib import Path
from unittest import TestCase from unittest import TestCase
import numpy as np
from factories.geometry_factory import GeometryFactory from factories.geometry_factory import GeometryFactory
from factories.weather_factory import WeatherFactory from factories.weather_factory import WeatherFactory
@ -21,21 +20,22 @@ class TestWeatherFactory(TestCase):
:return: :return:
""" """
self._city_gml = None self._city_gml = None
self._nyc_with_weather = None self._city_with_weather = None
self._city_name = 'new_york_city'
self._example_path = (Path(__file__).parent.parent / 'tests_data').resolve() self._example_path = (Path(__file__).parent.parent / 'tests_data').resolve()
def _get_citygml(self): def _get_citygml(self, file_path):
if self._city_gml is None: if self._city_gml is None:
file_path = (self._example_path / '20buildings.gml').resolve()
self._city_gml = GeometryFactory('citygml', file_path).city self._city_gml = GeometryFactory('citygml', file_path).city
self.assertIsNotNone(self._city_gml, 'city is none') self.assertIsNotNone(self._city_gml, 'city is none')
return self._city_gml return self._city_gml
def _get_city_with_weather(self): def _get_city_with_weather(self):
if self._nyc_with_weather is None: if self._city_with_weather is None:
self._nyc_with_weather = self._get_citygml() file_path = (Path(__file__).parent.parent / 'tests_data' / '20buildings.gml').resolve()
WeatherFactory('dat', self._nyc_with_weather, base_path=self._example_path) self._city_with_weather = self._get_citygml(file_path)
return self._nyc_with_weather WeatherFactory('dat', self._city_with_weather, city_name=self._city_name, base_path=self._example_path)
return self._city_with_weather
def test_city_with_weather(self): def test_city_with_weather(self):
""" """
@ -52,3 +52,13 @@ class TestWeatherFactory(TestCase):
self.assertFalse(values.empty, 'wrong value diffuse') self.assertFalse(values.empty, 'wrong value diffuse')
values = building.beam['hour'][['inseldb']] values = building.beam['hour'][['inseldb']]
self.assertFalse(values.empty, 'wrong value beam') self.assertFalse(values.empty, 'wrong value beam')
def test_weather_xls(self):
file_path = (Path(__file__).parent.parent / 'tests_data' / 'iso_52016_1_2017_lod2.gml').resolve()
city_with_weather = self._get_citygml(file_path)
WeatherFactory('xls', city_with_weather, city_name=self._city_name, base_path=self._example_path)
for building in city_with_weather.buildings:
values = building.external_temperature['hour'][['iso52016']]
self.assertFalse(values.empty, 'wrong value external_temperature')
values = building.global_horizontal['hour'][['iso52016']]
self.assertFalse(values.empty, 'wrong value global horizontal')

Binary file not shown.

View File

@ -0,0 +1,129 @@
<?xml version="1.0" encoding="UTF-8"?>
<core:CityModel xmlns:brid="http://www.opengis.net/citygml/bridge/2.0" xmlns:tran="http://www.opengis.net/citygml/transportation/2.0" xmlns:frn="http://www.opengis.net/citygml/cityfurniture/2.0" xmlns:wtr="http://www.opengis.net/citygml/waterbody/2.0" xmlns:sch="http://www.ascc.net/xml/schematron" xmlns:veg="http://www.opengis.net/citygml/vegetation/2.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:tun="http://www.opengis.net/citygml/tunnel/2.0" xmlns:tex="http://www.opengis.net/citygml/texturedsurface/2.0" xmlns:gml="http://www.opengis.net/gml" xmlns:gen="http://www.opengis.net/citygml/generics/2.0" xmlns:dem="http://www.opengis.net/citygml/relief/2.0" xmlns:app="http://www.opengis.net/citygml/appearance/2.0" xmlns:luse="http://www.opengis.net/citygml/landuse/2.0" xmlns:xAL="urn:oasis:names:tc:ciq:xsdschema:xAL:2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:smil20lang="http://www.w3.org/2001/SMIL20/Language" xmlns:pbase="http://www.opengis.net/citygml/profiles/base/2.0" xmlns:smil20="http://www.w3.org/2001/SMIL20/" xmlns:bldg="http://www.opengis.net/citygml/building/2.0" xmlns:core="http://www.opengis.net/citygml/2.0" xmlns:grp="http://www.opengis.net/citygml/cityobjectgroup/2.0">
<gml:boundedBy>
<gml:Envelope srsName="EPSG:32618" srsDimension="3">
<gml:lowerCorner>611249.8791199997 5039909.935869999 0</gml:lowerCorner>
<gml:upperCorner>611257.8791199997 5039915.935869999 2.6999999999970896</gml:upperCorner>
</gml:Envelope>
</gml:boundedBy>
<core:cityObjectMember>
<bldg:Building gml:id="gml_1">
<bldg:lod2Solid>
<gml:Solid srsName="EPSG:32618" srsDimension="3">
<gml:exterior>
<gml:CompositeSurface>
<gml:surfaceMember xlink:href="#UUID_d4d308ec-d4c2-4d11-82aa-e7f74d7813b4"/>
<gml:surfaceMember xlink:href="#UUID_f95ebeb8-8d79-4745-9c7a-24510f6966c9"/>
<gml:surfaceMember xlink:href="#UUID_f0b30655-0cc7-4fa7-82bb-06a2f2b49d43"/>
<gml:surfaceMember xlink:href="#UUID_325f2760-8a2d-4471-bf7c-fa29dc105c53"/>
<gml:surfaceMember xlink:href="#UUID_807ba20f-e2c3-4907-b23f-091d07f19ce0"/>
<gml:surfaceMember xlink:href="#UUID_dc447d8c-9509-4952-9f32-b565535e41c6"/>
</gml:CompositeSurface>
</gml:exterior>
</gml:Solid>
</bldg:lod2Solid>
<bldg:boundedBy>
<bldg:RoofSurface gml:id="gml_1_291db0ac-84ab-45be-b7cc-375f8ea66d67">
<bldg:lod2MultiSurface>
<gml:MultiSurface srsName="EPSG:32618" srsDimension="3">
<gml:surfaceMember>
<gml:Polygon gml:id="UUID_d4d308ec-d4c2-4d11-82aa-e7f74d7813b4">
<gml:exterior>
<gml:LinearRing>
<gml:posList>611257.8791199997 5039909.935869999 2.6999999999970896 611257.8791199997 5039915.935869999 2.6999999999970896 611249.8791199997 5039915.935869999 2.6999999999970896 611249.8791199997 5039909.935869999 2.6999999999970896 611257.8791199997 5039909.935869999 2.6999999999970896</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</bldg:lod2MultiSurface>
</bldg:RoofSurface>
</bldg:boundedBy>
<bldg:boundedBy>
<bldg:WallSurface gml:id="gml_1_2d005166-36d8-4bc4-a356-bbe042d5f65d">
<bldg:lod2MultiSurface>
<gml:MultiSurface srsName="EPSG:32618" srsDimension="3">
<gml:surfaceMember>
<gml:Polygon gml:id="UUID_f95ebeb8-8d79-4745-9c7a-24510f6966c9">
<gml:exterior>
<gml:LinearRing>
<gml:posList>611257.8791199997 5039909.935869999 0 611257.8791199997 5039909.935869999 2.6999999999970896 611249.8791199997 5039909.935869999 2.6999999999970896 611249.8791199997 5039909.935869999 0 611257.8791199997 5039909.935869999 0</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</bldg:lod2MultiSurface>
</bldg:WallSurface>
</bldg:boundedBy>
<bldg:boundedBy>
<bldg:WallSurface gml:id="gml_1_1906de88-0631-4346-b649-2865fbeeeeca">
<bldg:lod2MultiSurface>
<gml:MultiSurface srsName="EPSG:32618" srsDimension="3">
<gml:surfaceMember>
<gml:Polygon gml:id="UUID_f0b30655-0cc7-4fa7-82bb-06a2f2b49d43">
<gml:exterior>
<gml:LinearRing>
<gml:posList>611257.8791199997 5039915.935869999 0 611257.8791199997 5039915.935869999 2.6999999999970896 611257.8791199997 5039909.935869999 2.6999999999970896 611257.8791199997 5039909.935869999 0 611257.8791199997 5039915.935869999 0</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</bldg:lod2MultiSurface>
</bldg:WallSurface>
</bldg:boundedBy>
<bldg:boundedBy>
<bldg:WallSurface gml:id="gml_1_5741a50d-f423-4b74-a8bf-393341475a7e">
<bldg:lod2MultiSurface>
<gml:MultiSurface srsName="EPSG:32618" srsDimension="3">
<gml:surfaceMember>
<gml:Polygon gml:id="UUID_325f2760-8a2d-4471-bf7c-fa29dc105c53">
<gml:exterior>
<gml:LinearRing>
<gml:posList>611249.8791199997 5039915.935869999 0 611249.8791199997 5039915.935869999 2.6999999999970896 611257.8791199997 5039915.935869999 2.6999999999970896 611257.8791199997 5039915.935869999 0 611249.8791199997 5039915.935869999 0</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</bldg:lod2MultiSurface>
</bldg:WallSurface>
</bldg:boundedBy>
<bldg:boundedBy>
<bldg:WallSurface gml:id="gml_1_968ffb19-fe74-4f47-9a0b-65999895c56c">
<bldg:lod2MultiSurface>
<gml:MultiSurface srsName="EPSG:32618" srsDimension="3">
<gml:surfaceMember>
<gml:Polygon gml:id="UUID_807ba20f-e2c3-4907-b23f-091d07f19ce0">
<gml:exterior>
<gml:LinearRing>
<gml:posList>611249.8791199997 5039909.935869999 0 611249.8791199997 5039909.935869999 2.6999999999970896 611249.8791199997 5039915.935869999 2.6999999999970896 611249.8791199997 5039915.935869999 0 611249.8791199997 5039909.935869999 0</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</bldg:lod2MultiSurface>
</bldg:WallSurface>
</bldg:boundedBy>
<bldg:boundedBy>
<bldg:GroundSurface gml:id="gml_1_5c40b841-52b5-4624-bf1c-551c0a4459f7">
<bldg:lod2MultiSurface>
<gml:MultiSurface srsName="EPSG:32618" srsDimension="3">
<gml:surfaceMember>
<gml:Polygon gml:id="UUID_dc447d8c-9509-4952-9f32-b565535e41c6">
<gml:exterior>
<gml:LinearRing>
<gml:posList>611249.8791199997 5039909.935869999 0 611249.8791199997 5039915.935869999 0 611257.8791199997 5039915.935869999 0 611257.8791199997 5039909.935869999 0 611249.8791199997 5039909.935869999 0</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</bldg:lod2MultiSurface>
</bldg:GroundSurface>
</bldg:boundedBy>
</bldg:Building>
</core:cityObjectMember>
</core:CityModel>