Merge branch 'master' into review_usage_and_construction_catalogs

# Conflicts:
#	city_model_structure/building_demand/thermal_zone.py
#	imports/schedules/comnet_schedules_parameters.py
#	imports/schedules/doe_idf.py
#	imports/usage/comnet_usage_parameters.py
This commit is contained in:
Pilar 2022-12-06 14:25:56 -05:00
commit a038fbd31e
76 changed files with 258568 additions and 689 deletions

1
.gitignore vendored
View File

@ -5,3 +5,4 @@
/data/energy_systems/heat_pumps/*.csv
/data/energy_systems/heat_pumps/*.insel
.DS_Store
**/__pycache__/

View File

@ -164,7 +164,7 @@ When all the dependencies are satisfied, you are all set to start importing your
Add the following code to your main.py
from imports.geometry_factory import GeometryFactory
city = GeometryFactory('citygml', 'myfile.gml').city
city = GeometryFactory('citygml', path='myfile.gml').city
Always remember to push your own project changes as the last thing you do before ending your working day!
First, commit your changes by clicking on the green check in the top-right corner of Pycharm. Add a comment

View File

@ -237,7 +237,7 @@ Add the following code to your main.py
from imports.geometry_factory import GeometryFactory
city = GeometryFactory('citygml', 'myfile.gml').city
city = GeometryFactory('citygml', path='myfile.gml').city
```
9. Always remember to push your own project changes as the last thing you do before ending your working day!

View File

@ -116,7 +116,7 @@ class NrelCatalog(Catalog):
climate_zone = archetype['@climate_zone']
construction_period = reference_standard_to_construction_period[archetype['@reference_standard']]
average_storey_height = archetype['average_storey_height']['#text']
thermal_capacity = archetype['thermal_capacity']['#text']
thermal_capacity = str(float(archetype['thermal_capacity']['#text']) * 1000)
extra_loses_due_to_thermal_bridges = archetype['extra_loses_due_to_thermal_bridges']['#text']
indirect_heated_ratio = archetype['indirect_heated_ratio']['#text']
infiltration_rate_for_ventilation_system_off = archetype['infiltration_rate_for_ventilation_system_off']['#text']

View File

@ -12,7 +12,7 @@ Catalog = TypeVar('Catalog')
class GreeneryCatalogFactory:
"""
GeometryFactory class
GreeneryCatalogFactory class
"""
def __init__(self, file_type, base_path=None):
if base_path is None:

View File

@ -20,8 +20,8 @@ class Building(CityObject):
"""
Building(CityObject) class
"""
def __init__(self, name, lod, surfaces, year_of_construction, function, city_lower_corner, terrains=None):
super().__init__(name, lod, surfaces, city_lower_corner)
def __init__(self, name, surfaces, year_of_construction, function, terrains=None):
super().__init__(name, surfaces)
self._households = None
self._basement_heated = None
self._attic_heated = None
@ -38,6 +38,9 @@ class Building(CityObject):
self._type = 'building'
self._heating = dict()
self._cooling = dict()
self._lighting_electrical_demand = dict()
self._appliances_electrical_demand = dict()
self._domestic_hot_water_heat_demand = dict()
self._eave_height = None
self._grounds = []
self._roofs = []
@ -131,6 +134,9 @@ class Building(CityObject):
def attic_heated(self) -> Union[None, int]:
"""
Get if the city object attic is heated
0: no attic in the building
1: attic exists but is not heated
2: attic exists and is heated
:return: None or int
"""
return self._attic_heated
@ -139,6 +145,9 @@ class Building(CityObject):
def attic_heated(self, value):
"""
Set if the city object attic is heated
0: no attic in the building
1: attic exists but is not heated
2: attic exists and is heated
:param value: int
"""
if value is not None:
@ -148,6 +157,9 @@ class Building(CityObject):
def basement_heated(self) -> Union[None, int]:
"""
Get if the city object basement is heated
0: no basement in the building
1: basement exists but is not heated
2: basement exists and is heated
:return: None or int
"""
return self._basement_heated
@ -156,6 +168,9 @@ class Building(CityObject):
def basement_heated(self, value):
"""
Set if the city object basement is heated
0: no basement in the building
1: basement exists but is not heated
2: basement exists and is heated
:param value: int
"""
if value is not None:
@ -269,6 +284,54 @@ class Building(CityObject):
"""
self._cooling = value
@property
def lighting_electrical_demand(self) -> dict:
"""
Get lighting electrical demand in Wh
:return: dict{DataFrame(float)}
"""
return self._lighting_electrical_demand
@lighting_electrical_demand.setter
def lighting_electrical_demand(self, value):
"""
Set lighting electrical demand in Wh
:param value: dict{DataFrame(float)}
"""
self._lighting_electrical_demand = value
@property
def appliances_electrical_demand(self) -> dict:
"""
Get appliances electrical demand in Wh
:return: dict{DataFrame(float)}
"""
return self._appliances_electrical_demand
@appliances_electrical_demand.setter
def appliances_electrical_demand(self, value):
"""
Set appliances electrical demand in Wh
:param value: dict{DataFrame(float)}
"""
self._appliances_electrical_demand = value
@property
def domestic_hot_water_heat_demand(self) -> dict:
"""
Get domestic hot water heat demand in Wh
:return: dict{DataFrame(float)}
"""
return self._domestic_hot_water_heat_demand
@domestic_hot_water_heat_demand.setter
def domestic_hot_water_heat_demand(self, value):
"""
Set domestic hot water heat demand in Wh
:param value: dict{DataFrame(float)}
"""
self._domestic_hot_water_heat_demand = value
@property
def eave_height(self):
"""

View File

@ -9,6 +9,7 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord
import uuid
from typing import List, Union, TypeVar
from helpers.configuration_helper import ConfigurationHelper as ch
import helpers.constants as cte
from city_model_structure.building_demand.layer import Layer
from city_model_structure.building_demand.thermal_opening import ThermalOpening
from city_model_structure.building_demand.thermal_zone import ThermalZone
@ -213,13 +214,16 @@ class ThermalBoundary:
if self._u_value is None:
h_i = self.hi
h_e = self.he
if self.type == cte.GROUND:
r_value = 1.0 / h_i + ch().soil_thickness / ch().soil_conductivity
else:
r_value = 1.0/h_i + 1.0/h_e
try:
for layer in self.layers:
if layer.material.no_mass:
r_value += float(layer.material.thermal_resistance)
else:
r_value = r_value + float(layer.material.conductivity) / float(layer.thickness)
r_value += float(layer.thickness) / float(layer.material.conductivity)
self._u_value = 1.0/r_value
except TypeError:
raise Exception('Constructions layers are not initialized') from TypeError

View File

@ -76,7 +76,7 @@ class ThermalOpening:
if self._overall_u_value is None and self.thickness is not None:
h_i = self.hi
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.thickness) / float(self._conductivity)
self._overall_u_value = 1 / r_value
@property
@ -134,7 +134,7 @@ class ThermalOpening:
if self._overall_u_value is None and self.conductivity is not None:
h_i = self.hi
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._thickness) / float(self.conductivity)
self._overall_u_value = 1 / r_value
@property

View File

@ -52,26 +52,26 @@ class ThermalZone:
self._appliances = None
self._internal_gains = None
self._thermal_control = None
self._usage_zones = None
self._usages = None
@property
def usage_zones(self):
# example 70-office_30-residential
if self._usage_from_parent:
self._usage_zones = copy.deepcopy(self._parent_internal_zone.usage_zones)
self._usages = copy.deepcopy(self._parent_internal_zone.usage_zones)
else:
values = self._usage.split('_')
usages = []
for value in values:
usages.append(value.split('-'))
self._usage_zones = []
for parent_usage_zone in self._parent_internal_zone.usage_zones:
self._usages = []
for parent_usage in self._parent_internal_zone.usage_zones:
for value in usages:
if parent_usage_zone.name == value[1]:
new_usage_zone = copy.deepcopy(parent_usage_zone)
new_usage_zone.percentage = float(value[0])/100
self._usage_zones.append(new_usage_zone)
return self._usage_zones
if parent_usage.usage == value[1]:
new_usage = copy.deepcopy(parent_usage)
new_usage.percentage = float(value[0])/100
self._usages.append(new_usage)
return self._usages
@property
def id(self):
@ -102,7 +102,7 @@ class ThermalZone:
@property
def additional_thermal_bridge_u_value(self) -> Union[None, float]:
"""
Get thermal zone additional thermal bridge u value W/m2K
Get thermal zone additional thermal bridge u value per footprint area W/m2K
:return: None or float
"""
return self._additional_thermal_bridge_u_value
@ -110,7 +110,7 @@ class ThermalZone:
@additional_thermal_bridge_u_value.setter
def additional_thermal_bridge_u_value(self, value):
"""
Set thermal zone additional thermal bridge u value W/m2K
Set thermal zone additional thermal bridge u value per footprint area W/m2K
:param value: float
"""
if value is not None:
@ -234,7 +234,7 @@ class ThermalZone:
return None
self._usage = ''
for usage_zone in self._parent_internal_zone.usage_zones:
self._usage += str(round(usage_zone.percentage * 100)) + '-' + usage_zone.name + '_'
self._usage += str(round(usage_zone.percentage * 100)) + '-' + usage_zone.usage + '_'
self._usage = self._usage[:-1]
return self._usage

View File

@ -17,8 +17,8 @@ class BusSystem(CityObject):
"""
BusSystem(CityObject) class
"""
def __init__(self, name, lod, surfaces, city_lower_corner):
super().__init__(name, lod, surfaces, city_lower_corner)
def __init__(self, name, surfaces, city_lower_corner):
super().__init__(name, surfaces, city_lower_corner)
self._bus_routes = None
self._bus_network = None
self._buses = None

View File

@ -21,6 +21,7 @@ from city_model_structure.city_objects_cluster import CityObjectsCluster
from city_model_structure.buildings_cluster import BuildingsCluster
from city_model_structure.fuel import Fuel
from city_model_structure.iot.station import Station
from city_model_structure.level_of_detail import LevelOfDetail
from city_model_structure.machine import Machine
from city_model_structure.parts_consisting_building import PartsConsistingBuilding
from city_model_structure.subway_entrance import SubwayEntrance
@ -29,6 +30,7 @@ from helpers.location import Location
from city_model_structure.energy_system import EnergySystem
from city_model_structure.lca_material import LcaMaterial
class City:
"""
City class
@ -59,6 +61,7 @@ class City:
self._machines = None
self._stations = []
self._lca_materials = None
self._level_of_detail = LevelOfDetail()
@property
def fuels(self) -> [Fuel]:
@ -287,7 +290,6 @@ class City:
selected_region_upper_corner = [center[0] + radius, center[1] + radius, center[2] + radius]
selected_region_city = City(selected_region_lower_corner, selected_region_upper_corner, srs_name=self.srs_name)
selected_region_city.climate_file = self.climate_file
# selected_region_city.climate_reference_city = self.climate_reference_city
for city_object in self.city_objects:
location = city_object.centroid
if location is not None:
@ -426,9 +428,9 @@ class City:
"""
self._lca_materials = value
def lca_material(self, lca_id) -> LcaMaterial:
def lca_material(self, lca_id) -> Union[LcaMaterial, None]:
"""
Get the lca materiol matching the given Id
Get the lca material matching the given Id
:return: LcaMaterial or None
"""
for lca_material in self.lca_materials:
@ -448,3 +450,11 @@ class City:
for city_object in city.city_objects:
_merge_city.add_city_object(city_object)
return _merge_city
@property
def level_of_detail(self) -> LevelOfDetail:
"""
Get level of detail of different aspects of the city: geometry, construction and usage
:return: LevelOfDetail
"""
return self._level_of_detail

View File

@ -18,11 +18,9 @@ class CityObject:
"""
class CityObject
"""
def __init__(self, name, lod, surfaces, city_lower_corner):
def __init__(self, name, surfaces):
self._name = name
self._lod = lod
self._surfaces = surfaces
self._city_lower_corner = city_lower_corner
self._type = None
self._city_object_lower_corner = None
self._detailed_polyhedron = None
@ -45,15 +43,6 @@ class CityObject:
"""
return self._name
@property
def lod(self) -> int:
"""
Get city object level of detail 1, 2, 3 or 4
:return: int
"""
lod = int(math.log(self._lod, 2) + 1)
return lod
@property
def type(self) -> str:
"""
@ -236,3 +225,5 @@ class CityObject:
:param value: [Sensor]
"""
self._sensors = value

View File

@ -20,8 +20,7 @@ class CityObjectsCluster(ABC, CityObject):
self._cluster_type = cluster_type
self._city_objects = city_objects
self._sensors = []
self._lod = ''
super().__init__(name, self._lod, None, None)
super().__init__(name, None)
@property
def name(self):

View File

@ -16,8 +16,8 @@ class EnergySystem(CityObject):
EnergySystem(CityObject) class
"""
def __init__(self, name, lod, surfaces, city_lower_corner):
super().__init__(name, lod, surfaces, city_lower_corner)
def __init__(self, name, surfaces):
super().__init__(name, surfaces)
self._air_source_hp = None
self._water_to_water_hp = None
self._type = 'energy_system'

View File

@ -0,0 +1,61 @@
"""
Level of detail module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
class LevelOfDetail:
"""
Level of detail for the city class
"""
def __init__(self):
self._geometry = None
self._construction = None
self._usage = None
@property
def geometry(self):
"""
Get the city minimal geometry level of detail from 0 to 4
:return: int
"""
return self._geometry
@geometry.setter
def geometry(self, value):
"""
Set the city minimal geometry level of detail from 0 to 4
"""
self._geometry = value
@property
def construction(self):
"""
Get the city minimal construction level of detail, 1 or 2
:return: int
"""
return self._construction
@construction.setter
def construction(self, value):
"""
Set the city minimal construction level of detail, 1 or 2
"""
self._construction = value
@property
def usage(self):
"""
Get the city minimal usage level of detail, 1 or 2
:return: int
"""
return self._usage
@usage.setter
def usage(self, value):
"""
Set the city minimal usage level of detail, 1 or 2
"""
self._usage = value

View File

@ -12,7 +12,7 @@ class SubwayEntrance(CityObject):
SubwayEntrance(CityObject) class
"""
def __init__(self, name, latitude, longitude):
super().__init__(0, [], name, [])
super().__init__(name, 0, [])
self._name = name
self._latitude = latitude
self._longitude = longitude

View File

@ -11,5 +11,10 @@ comnet_occupancy_sensible_radiant = 0.1
comnet_plugs_latent = 0
comnet_plugs_convective = 0.75
comnet_plugs_radiant = 0.25
#W/m2K
convective_heat_transfer_coefficient_interior = 3.5
convective_heat_transfer_coefficient_exterior = 20
#W/mK
soil_conductivity = 3
#m
soil_thickness = 0.5

View File

@ -7,7 +7,6 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord
Soroush Samareh Abolhassani soroush.samarehabolhassani@mail.concordia.ca
"""
import copy
import math
from pathlib import Path
from geomeppy import IDF
import helpers.constants as cte
@ -51,17 +50,12 @@ class Idf:
_LOCATION = 'SITE:LOCATION'
_SIMPLE = 'Simple'
idf_surfaces = {
# todo: make an enum for all the surface types
cte.WALL: 'wall',
cte.GROUND: 'floor',
cte.ROOF: 'roof'
}
idf_usage = {
# todo: make an enum for all the usage types
cte.RESIDENTIAL: 'residential_building'
}
idf_type_limits = {
cte.ON_OFF: 'on/off',
cte.FRACTION: 'Fraction',
@ -81,20 +75,6 @@ class Idf:
cte.WINTER_DESIGN_DAY: 'WinterDesignDay',
cte.SUMMER_DESIGN_DAY: 'SummerDesignDay'
}
idf_schedule_types = {
'compact': 'Compact',
cte.DAY: 'Day',
cte.WEEK: 'Week',
cte.YEAR: 'Year',
'file': 'File'
}
idf_schedule_data_type = {
'compact': 'Compact',
'hourly': 'Hourly',
'daily': 'Daily',
'interval': 'Interval',
'list': 'List',
}
def __init__(self, city, output_path, idf_file_path, idd_file_path, epw_file_path, export_type="Surfaces",
target_buildings=None, adjacent_buildings=None):
@ -120,6 +100,7 @@ class Idf:
self._adjacent_buildings = []
self._export()
@staticmethod
def _matrix_to_list(points, lower_corner):
lower_x = lower_corner[0]
@ -395,6 +376,7 @@ class Idf:
self._remove_location()
self._remove_sizing_periods()
self._rename_building(self._city.name)
self._lod = self._city.level_of_detail.geometry
for building in self._city.buildings:
for internal_zone in building.internal_zones:
@ -518,19 +500,22 @@ class Idf:
self._city.lower_corner)
surface.setcoords(coordinates)
self._add_windows(boundary)
def _add_windows(self, boundary):
for opening in boundary.thermal_openings:
for construction in self._idf.idfobjects[self._CONSTRUCTION]:
if construction['Outside_Layer'].split('_')[0] == 'glazing':
window_construction = construction
if self._compare_window_constructions(window_construction, opening):
opening_name = 'window_' + str(len(self._idf.idfobjects[self._WINDOW]) + 1)
opening_length = math.sqrt(opening.area)
self._idf.newidfobject(self._WINDOW, Name=f'{opening_name}', Construction_Name=window_construction['Name'],
Building_Surface_Name=boundary.parent_surface.name, Multiplier='1',
Length=opening_length, Height=opening_length)
if self._lod >= 3:
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones:
for boundary in thermal_zone.thermal_boundaries:
self._add_windows_by_vertices(boundary)
else:
# idf only allows setting wwr for external walls
wwr = 0
for surface in building.surfaces:
if surface.type == cte.WALL:
wwr = surface.associated_thermal_boundaries[0].window_ratio
self._idf.set_wwr(wwr, construction='glazing_1')
def _add_windows_by_vertices(self, boundary):
raise NotImplementedError
def _compare_window_constructions(self, window_construction, opening):
glazing = window_construction['Outside_Layer']

View File

@ -0,0 +1,195 @@
"""
InselMonthlyEnergyBalance exports models to insel format
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import numpy as np
from pathlib import Path
from exports.formats.insel import Insel
from imports.weather.helpers.weather import Weather
import helpers.constants as cte
_CONSTRUCTION_CODE = {
cte.WALL: '1',
cte.GROUND: '2',
cte.ROOF: '3',
cte.INTERIOR_WALL: '5',
cte.GROUND_WALL: '6',
cte.ATTIC_FLOOR: '7',
cte.INTERIOR_SLAB: '8'
}
class InselMonthlyEnergyBalance(Insel):
def __init__(self, city, path, radiation_calculation_method='sra', weather_format='epw'):
super().__init__(city, path)
self._radiation_calculation_method = radiation_calculation_method
self._weather_format = weather_format
self._contents = []
self._insel_files_paths = []
for building in city.buildings:
self._insel_files_paths.append(building.name + '.insel')
file_name_out = building.name + '.out'
output_path = Path(self._path / file_name_out).resolve()
self._contents.append(self.generate_meb_template(building, output_path, self._radiation_calculation_method,
self._weather_format))
self._export()
def _export(self):
for i_file, content in enumerate(self._contents):
file_name = self._insel_files_paths[i_file]
with open(Path(self._path / file_name).resolve(), 'w') as insel_file:
insel_file.write(content)
return
@staticmethod
def generate_meb_template(building, insel_outputs_path, radiation_calculation_method, weather_format):
file = ""
i_block = 1
parameters = ["1", "12", "1"]
file = Insel._add_block(file, i_block, 'DO', parameters=parameters)
i_block = 4
inputs = ["1.1", "20.1", "21.1"]
surfaces = building.surfaces
for i in range(1, len(surfaces) + 1):
inputs.append(f"{str(100 + i)}.1 % Radiation surface {str(i)}")
# BUILDING PARAMETERS
parameters = [f'{0.85 * building.volume} % BP(1) Heated Volume (m3)',
f'{building.average_storey_height} % BP(2) Average storey height (m)',
f'{building.storeys_above_ground} % BP(3) Number of storeys above ground',
f'{building.attic_heated} % BP(4) Attic heating type (0=no room, 1=unheated, 2=heated)',
f'{building.basement_heated} % BP(5) Cellar heating type (0=no room, 1=unheated, 2=heated, '
f'99=invalid)']
# todo: this method and the insel model have to be reviewed for more than one internal zone
internal_zone = building.internal_zones[0]
thermal_zone = internal_zone.thermal_zones[0]
parameters.append(f'{thermal_zone.indirectly_heated_area_ratio} % BP(6) Indirectly heated area ratio')
parameters.append(f'{thermal_zone.effective_thermal_capacity / 3600} % BP(7) Effective heat capacity (Wh/m2K)')
parameters.append(f'{thermal_zone.additional_thermal_bridge_u_value} '
f'% BP(8) Additional U-value for heat bridge (Wh/m2K)')
parameters.append('1 % BP(9) Usage type (0=standard, 1=IWU)')
# ZONES AND SURFACES
parameters.append(f'{len(internal_zone.usage_zones)} % BP(10) Number of zones')
for i, usage_zone in enumerate(internal_zone.usage_zones):
percentage_usage = usage_zone.percentage
parameters.append(f'{float(internal_zone.area) * percentage_usage} % BP(11) #1 Area of zone {i + 1} (m2)')
total_internal_gain = 0
for ig in usage_zone.internal_gains:
total_internal_gain += float(ig.average_internal_gain) * \
(float(ig.convective_fraction) + float(ig.radiative_fraction))
parameters.append(f'{total_internal_gain} % BP(12) #2 Internal gains of zone {i + 1}')
parameters.append(f'{usage_zone.thermal_control.mean_heating_set_point} % BP(13) #3 Heating setpoint temperature '
f'zone {i + 1} (degree Celsius)')
parameters.append(f'{usage_zone.thermal_control.heating_set_back} % BP(14) #4 Heating setback temperature '
f'zone {i + 1} (degree Celsius)')
parameters.append(f'{usage_zone.thermal_control.mean_cooling_set_point} % BP(15) #5 Cooling setpoint temperature '
f'zone {i + 1} (degree Celsius)')
parameters.append(f'{usage_zone.hours_day} % BP(16) #6 Usage hours per day zone {i + 1}')
parameters.append(f'{usage_zone.days_year} % BP(17) #7 Usage days per year zone {i + 1}')
parameters.append(f'{usage_zone.mechanical_air_change} % BP(18) #8 Minimum air change rate zone {i + 1} (ACH)')
parameters.append(f'{len(thermal_zone.thermal_boundaries)} % Number of surfaces = BP(11+8z) \n'
f'% 1. Surface type (1=wall, 2=ground 3=roof, 4=flat roof)\n'
f'% 2. Areas above ground (m2)\n'
f'% 3. Areas below ground (m2)\n'
f'% 4. U-value (W/m2K)\n'
f'% 5. Window area (m2)\n'
f'% 6. Window frame fraction\n'
f'% 7. Window U-value (W/m2K)\n'
f'% 8. Window g-value\n'
f'% 9. Short-wave reflectance\n'
f'% #1 #2 #3 #4 #5 #6 #7 #8 #9\n')
for thermal_boundary in thermal_zone.thermal_boundaries:
type_code = _CONSTRUCTION_CODE[thermal_boundary.type]
window_area = thermal_boundary.opaque_area * thermal_boundary.window_ratio / (1 - thermal_boundary.window_ratio)
parameters.append(type_code)
if thermal_boundary.type != cte.GROUND:
parameters.append(thermal_boundary.opaque_area + window_area)
parameters.append('0.0')
else:
parameters.append('0.0')
parameters.append(thermal_boundary.opaque_area + window_area)
parameters.append(thermal_boundary.u_value)
parameters.append(window_area)
if window_area <= 0.001:
parameters.append(0.0)
parameters.append(0.0)
parameters.append(0.0)
else:
thermal_opening = thermal_boundary.thermal_openings[0]
parameters.append(thermal_opening.frame_ratio)
parameters.append(thermal_opening.overall_u_value)
parameters.append(thermal_opening.g_value)
if thermal_boundary.type is not cte.GROUND:
parameters.append(thermal_boundary.parent_surface.short_wave_reflectance)
else:
parameters.append(0.0)
file = Insel._add_block(file, i_block, 'd18599', inputs=inputs, parameters=parameters)
i_block = 20
inputs = ['1']
parameters = ['12 % Monthly ambient temperature (degree Celsius)']
external_temperature = building.external_temperature[cte.MONTH]
for i in range(0, len(external_temperature)):
parameters.append(f'{i + 1} {external_temperature.at[i, weather_format]}')
file = Insel._add_block(file, i_block, 'polyg', inputs=inputs, parameters=parameters)
i_block = 21
inputs = ['1']
parameters = ['12 % Monthly sky temperature']
sky_temperature = Weather.sky_temperature(external_temperature[[weather_format]].to_numpy().T[0])
for i, temperature in enumerate(sky_temperature):
parameters.append(f'{i + 1} {temperature}')
file = Insel._add_block(file, i_block, 'polyg', inputs=inputs, parameters=parameters)
for i, surface in enumerate(surfaces):
i_block = 101 + i
inputs = ['1 % Monthly surface radiation (W/m2)']
parameters = [f'12 % Azimuth {np.rad2deg(surface.azimuth)}, '
f'inclination {np.rad2deg(surface.inclination)} (degrees)']
if surface.type != 'Ground':
global_irradiance = surface.global_irradiance[cte.MONTH]
for j in range(0, len(global_irradiance)):
parameters.append(f'{j + 1} {global_irradiance.at[j, radiation_calculation_method]}')
else:
for j in range(0, 12):
parameters.append(f'{j + 1} 0.0')
file = Insel._add_block(file, i_block, 'polyg', inputs=inputs, parameters=parameters)
i_block = 300
inputs = ['4.1', '4.2']
file = Insel._add_block(file, i_block, 'cum', inputs=inputs)
i_block = 303
inputs = ['300.1', '300.2']
file = Insel._add_block(file, i_block, 'atend', inputs=inputs)
i_block = 310
inputs = ['4.1', '4.2']
parameters = ['1 % Mode',
'0 % Suppress FNQ inputs',
f"'{str(insel_outputs_path)}' % File name",
"'*' % Fortran format"]
file = Insel._add_block(file, i_block, 'WRITE', inputs=inputs, parameters=parameters)
return file

View File

@ -0,0 +1,74 @@
"""
EnergyBuildingsExportsFactory exports a city into several formats related to energy in buildings
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de uribarri pilar.monsalvete@concordia.ca
"""
from pathlib import Path
from exports.building_energy.energy_ade import EnergyAde
from exports.building_energy.idf import Idf
from exports.building_energy.insel.insel_monthly_energy_balance import InselMonthlyEnergyBalance
class EnergyBuildingsExportsFactory:
"""
Energy Buildings exports factory class
"""
def __init__(self, export_type, city, path, target_buildings=None, adjacent_buildings=None):
self._city = city
self._export_type = '_' + export_type.lower()
if isinstance(path, str):
path = Path(path)
self._path = path
self._target_buildings = target_buildings
self._adjacent_buildings = adjacent_buildings
@property
def _energy_ade(self):
"""
Export to citygml with application domain extensions
:return: None
"""
return EnergyAde(self._city, self._path)
@property
def _idf(self):
"""
Export the city to Energy+ idf format
When target_buildings is set, only those will be calculated and their energy consumption output, non adjacent
buildings will be considered shading objects and adjacent buildings will be considered adiabatic.
Adjacent buildings are provided they will be considered heated so energy plus calculations are more precise but
no results will be calculated to speed up the calculation process.
:return: None
"""
idf_data_path = (Path(__file__).parent / './building_energy/idf_files/').resolve()
# todo: create a get epw file function based on the city
weather_path = (Path(__file__).parent / '../data/weather/epw/CAN_PQ_Montreal.Intl.AP.716270_CWEC.epw').resolve()
return Idf(self._city, self._path, (idf_data_path / 'Minimal.idf'), (idf_data_path / 'Energy+.idd'), weather_path,
target_buildings=self._target_buildings, adjacent_buildings=self._adjacent_buildings)
@property
def _insel_monthly_energy_balance(self):
"""
Export to Insel MonthlyEnergyBalance
:return: None
"""
return InselMonthlyEnergyBalance(self._city, self._path)
def export(self):
"""
Export the city given to the class using the given export type handler
:return: None
"""
return getattr(self, self._export_type, lambda: None)
def export_debug(self):
"""
Export the city given to the class using the given export type handler
:return: None
"""
return getattr(self, self._export_type)

View File

@ -6,8 +6,6 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
from pathlib import Path
from exports.formats.energy_ade import EnergyAde
from exports.formats.idf import Idf
from exports.formats.obj import Obj
from exports.formats.simplified_radiosity_algorithm import SimplifiedRadiosityAlgorithm
from exports.formats.stl import Stl
@ -38,14 +36,6 @@ class ExportsFactory:
def _collada(self):
raise NotImplementedError
@property
def _energy_ade(self):
"""
Export to citygml with application domain extensions
:return: None
"""
return EnergyAde(self._city, self._path)
@property
def _stl(self):
"""
@ -70,25 +60,6 @@ class ExportsFactory:
"""
return Obj(self._city, self._path).to_ground_points()
@property
def _idf(self):
"""
Export the city to Energy+ idf format
When target_buildings is set, only those will be calculated and their energy consumption output, non adjacent
buildings will be considered shading objects and adjacent buildings will be considered adiabatic.
Adjacent buildings are provided they will be considered heated so energy plus calculations are more precise but
no results will be calculated to speed up the calculation process.
:return: None
"""
idf_data_path = (Path(__file__).parent / './formats/idf_files/').resolve()
# todo: create a get epw file function based on the city
weather_path = (Path(__file__).parent / '../data/weather/epw/CAN_PQ_Montreal.Intl.AP.716270_CWEC.epw').resolve()
return Idf(self._city, self._path, (idf_data_path / 'Minimal.idf'), (idf_data_path / 'Energy+.idd'), weather_path,
target_buildings=self._target_buildings, adjacent_buildings=self._adjacent_buildings)
@property
def _sra(self):
"""
@ -110,4 +81,4 @@ class ExportsFactory:
Export the city given to the class using the given export type handler
:return: None
"""
return getattr(self, self._export_type)
return Obj(self._city, self._path)

30
exports/formats/insel.py Normal file
View File

@ -0,0 +1,30 @@
"""
Insel export models to insel format
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from abc import ABC
class Insel(ABC):
def __init__(self, city, path):
self._city = city
self._path = path
self._results = None
@staticmethod
def _add_block(file, block_number, block_type, inputs='', parameters=''):
file += "S " + str(block_number) + " " + block_type + "\n"
for block_input in inputs:
file += str(block_input) + "\n"
if len(parameters) > 0:
file += "P " + str(block_number) + "\n"
for block_parameter in parameters:
file += str(block_parameter) + "\n"
return file
def _export(self):
raise NotImplementedError

View File

@ -26,7 +26,7 @@ class Obj(Triangular):
file_name_out = self._city.name + '_ground.' + self._triangular_format
file_path_in = (Path(self._path).resolve() / file_name_in).resolve()
file_path_out = (Path(self._path).resolve() / file_name_out).resolve()
scene = GeometryFactory('obj', file_path_in).scene
scene = GeometryFactory('obj', path=file_path_in).scene
scene.rezero()
obj_file = trimesh.exchange.obj.export_obj(scene)
with open(file_path_out, 'w') as file:

View File

@ -111,7 +111,7 @@ class ConfigurationHelper:
def convective_heat_transfer_coefficient_interior(self) -> float:
"""
Get configured convective heat transfer coefficient for surfaces inside the building
:return: 3.5
:return: 3.5 W/m2K
"""
return self._config.getfloat('buildings', 'convective_heat_transfer_coefficient_interior').real
@ -119,6 +119,22 @@ class ConfigurationHelper:
def convective_heat_transfer_coefficient_exterior(self) -> float:
"""
Get configured convective heat transfer coefficient for surfaces outside the building
:return: 20
:return: 20 W/m2K
"""
return self._config.getfloat('buildings', 'convective_heat_transfer_coefficient_exterior').real
@property
def soil_conductivity(self) -> float:
"""
Get configured soil conductivity for surfaces touching the ground
:return: 3 W/mK
"""
return self._config.getfloat('buildings', 'soil_conductivity').real
@property
def soil_thickness(self) -> float:
"""
Get configured soil thickness for surfaces touching the ground
:return: 0.5
"""
return self._config.getfloat('buildings', 'soil_thickness').real

View File

@ -6,7 +6,6 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
# universal constants
import sys
KELVIN = 273.15

View File

@ -1,104 +0,0 @@
"""
Enrich city
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from imports.construction_factory import ConstructionFactory
from imports.usage_factory import UsageFactory
from imports.schedules_factory import SchedulesFactory
class EnrichCity:
"""
Enrich city
"""
def __init__(self, city):
self._city = city
self._enriched_city = None
self._errors = []
@property
def errors(self) -> [str]:
"""
Error list
"""
return self._errors
def enriched_city(self, construction_format=None, usage_format=None, schedules_format=None,
pickle_construction=False, pickle_usage=False, pickle_schedules=False):
"""
Enrich the city with the given formats
:return: City
"""
if self._enriched_city is None:
self._errors = []
print('original:', len(self._city.buildings))
if not pickle_construction:
if construction_format is not None:
self._enriched_city = self._construction(construction_format)
if len(self._errors) != 0:
return self._enriched_city
if not pickle_usage:
if usage_format is not None:
self._enriched_city = self._usage(usage_format)
if len(self._errors) != 0:
return self._enriched_city
if not pickle_schedules:
if schedules_format is not None:
self._enriched_city = self._schedules(schedules_format)
if len(self._errors) != 0:
return self._enriched_city
self._enriched_city = self._city
return self._enriched_city
def _construction(self, construction_format):
ConstructionFactory(construction_format, self._city).enrich()
for building in self._city.buildings:
# infiltration_rate_system_off is a mandatory parameter.
# If it is not returned, extract the building from the calculation list
if len(building.thermal_zones) == 0:
self._city.remove_city_object(building)
elif building.thermal_zones[0].infiltration_rate_system_off is None:
self._city.remove_city_object(building)
if self._city.buildings is None:
self._errors.append('no archetype found per construction')
self._enriched_city = self._city
return self._enriched_city
print('enriched with construction:', len(self._city.buildings))
return self._city
def _usage(self, usage_format):
UsageFactory(usage_format, self._city).enrich()
for building in self._city.buildings:
# At least one thermal zone must be created.
# If it is not created, extract the building from the calculation list
if len(building.usage_zones) <= 0:
self._city.remove_city_object(building)
if self._city.buildings is None:
self._errors.append('no archetype found per usage')
self._enriched_city = self._city
return self._enriched_city
print('enriched with usage:', len(self._city.buildings))
return self._city
def _schedules(self, schedules_format):
SchedulesFactory(schedules_format, self._city).enrich()
for building in self._city.buildings:
counter_schedules = 0
for usage_zone in building.usage_zones:
# At least one schedule must be created at each thermal zone.
# If it is not created, extract the building from the calculation list
if len(usage_zone.schedules) > 0:
counter_schedules += 1
if counter_schedules < len(building.usage_zones):
self._city.remove_city_object(building)
if self._city.buildings is None:
self._errors.append('no archetype found per usage')
self._enriched_city = self._city
return self._enriched_city
print('enriched with occupancy:', len(self._city.buildings))
return self._city

View File

@ -20,6 +20,9 @@ class GeometryHelper:
"""
Geometry helper class
"""
srs_transformations = {
'urn:adv:crs:ETRS89_UTM32*DE_DHHN92_NH': 'epsg:25832'
}
def __init__(self, delta=0, area_delta=0):
self._delta = delta

47
helpers/monthly_values.py Normal file
View File

@ -0,0 +1,47 @@
"""
Monthly values
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Pilar Monsalvete pilar_monsalvete@yahoo.es
"""
import pandas as pd
import numpy as np
import calendar as cal
class MonthlyValues:
def __init__(self):
self._month_hour = None
def get_mean_values(self, values):
out = None
if values is not None:
if 'month' not in values.columns:
values = pd.concat([self.month_hour, pd.DataFrame(values)], axis=1)
out = values.groupby('month', as_index=False).mean()
del out['month']
return out
def get_total_month(self, values):
out = None
if values is not None:
if 'month' not in values.columns:
values = pd.concat([self.month_hour, pd.DataFrame(values)], axis=1)
out = pd.DataFrame(values).groupby('month', as_index=False).sum()
del out['month']
return out
@property
def month_hour(self):
"""
returns a DataFrame that has x values of the month number (January = 1, February = 2...),
being x the number of hours of the corresponding month
:return: DataFrame(int)
"""
array = []
for i in range(0, 12):
days_of_month = cal.monthrange(2015, i+1)[1]
total_hours = days_of_month * 24
array = np.concatenate((array, np.full(total_hours, i + 1)))
self._month_hour = pd.DataFrame(array, columns=['month'])
return self._month_hour

View File

@ -60,7 +60,7 @@ class BuildingArchetype:
@property
def additional_thermal_bridge_u_value(self):
"""
Get archetype's additional U value due to thermal bridges in W/m2K
Get archetype's additional U value due to thermal bridges per area of shell in W/m2K
:return: float
"""
return self._additional_thermal_bridge_u_value

View File

@ -74,7 +74,7 @@ class UsPhysicsParameters(NrelPhysicsInterface):
if (str(function) == str(building_archetype.function)) and \
(climate_zone == str(building_archetype.climate_zone)):
return building_archetype
return None
raise KeyError('archetype not found')
@staticmethod
def _search_construction_in_archetype(archetype, construction_type):

View File

@ -24,6 +24,7 @@ class ConstructionFactory:
Enrich the city by using NREL information
"""
UsPhysicsParameters(self._city, self._base_path).enrich_buildings()
self._city.level_of_detail.construction = 2
def enrich(self):
"""
@ -31,3 +32,10 @@ class ConstructionFactory:
:return: None
"""
getattr(self, self._handler, lambda: None)()
def enrich_debug(self):
"""
Enrich the city given to the class using the class given handler
:return: None
"""
UsPhysicsParameters(self._city, self._base_path).enrich_buildings()

View File

@ -82,7 +82,7 @@ class AirSourceHeatPumpParameters:
heat_pump.heating_comp_power = h_data[1]
heat_pump.heating_capacity_coff = self._compute_coefficients(h_data)
energy_system = EnergySystem('{} capacity heat pump'.format(heat_pump.model), 0, [], None)
energy_system = EnergySystem('{} capacity heat pump'.format(heat_pump.model), [])
energy_system.air_source_hp = heat_pump
self._city.add_city_object(energy_system)
return self._city

View File

@ -129,7 +129,7 @@ class WaterToWaterHPParameters:
heat_pump.entering_water_temp = data['ewt']
heat_pump.leaving_water_temp = data['lwt']
heat_pump.power_demand_coff = self._compute_coefficients(data)
energy_system = EnergySystem(heat_pump.model, 0, [], None)
energy_system = EnergySystem(heat_pump.model, [])
energy_system.water_to_water_hp = heat_pump
self._city.add_city_object(energy_system)
return self._city

View File

@ -21,10 +21,14 @@ class CityGml:
"""
CityGml class
"""
def __init__(self, path):
def __init__(self, path, extrusion_height_field=None, year_of_construction_field=None, function_field=None):
self._city = None
self._lod = None
self._lod1_tags = ['lod1Solid', 'lod1MultiSurface']
self._lod2_tags = ['lod2Solid', 'lod2MultiSurface', 'lod2MultiCurve']
self._extrusion_height_field = extrusion_height_field
self._year_of_construction_field = year_of_construction_field
self._function_field = function_field
self._lower_corner = None
self._upper_corner = None
with open(path) as gml:
@ -64,6 +68,9 @@ class CityGml:
self._upper_corner = np.fromstring(envelope['upperCorner'], dtype=float, sep=' ')
if '@srsName' in envelope:
self._srs_name = envelope['@srsName']
else:
# If not coordinate system given assuming hub standard
self._srs_name = "EPSG:26911"
else:
# get the boundary from the city objects instead
for city_object_member in self._gml['CityModel']['cityObjectMember']:
@ -74,8 +81,6 @@ class CityGml:
continue
envelope = bound['Envelope']
self._srs_name = envelope['@srsName']
lower_corner = None
upper_corner = None
if '#text' in envelope['lowerCorner']:
lower_corner = np.fromstring(envelope['lowerCorner']['#text'], dtype=float, sep=' ')
upper_corner = np.fromstring(envelope['upperCorner']['#text'], dtype=float, sep=' ')
@ -110,14 +115,16 @@ class CityGml:
if 'function' in city_object:
function = city_object['function']
if any(key in city_object for key in self._lod1_tags):
lod = 1
if self._lod is None or self._lod > 1:
self._lod = 1
surfaces = CityGmlLod1(city_object).surfaces
elif any(key in city_object for key in self._lod2_tags):
lod = 2
if self._lod is None or self._lod > 2:
self._lod = 2
surfaces = CityGmlLod2(city_object).surfaces
else:
raise NotImplementedError("Not supported level of detail")
return Building(name, lod, surfaces, year_of_construction, function, self._lower_corner, terrains=None)
return Building(name, surfaces, year_of_construction, function, terrains=None)
def _create_parts_consisting_building(self, city_object):
name = city_object['@id']
@ -143,4 +150,5 @@ class CityGml:
self._city.add_city_objects_cluster(self._create_parts_consisting_building(city_object))
else:
self._city.add_city_object(self._create_building(city_object))
self._city.level_of_detail.geometry = self._lod
return self._city

View File

@ -24,18 +24,6 @@ class CityGmlBase(ABC):
"""
return self._surfaces
@staticmethod
def _remove_last_point(points):
array = points.split(' ')
res = " "
return res.join(array[0:len(array) - 3])
@staticmethod
def _solid_points(coordinates) -> np.ndarray:
solid_points = np.fromstring(coordinates, dtype=float, sep=' ')
solid_points = GeometryHelper.to_points_matrix(solid_points)
return solid_points
@classmethod
def _solid(cls, city_object_member):
raise NotImplementedError

View File

@ -6,6 +6,7 @@ Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
from imports.geometry.helpers.geometry_helper import GeometryHelper
from imports.geometry.citygml_classes.citygml_base import CityGmlBase
from city_model_structure.building_demand.surface import Surface
from city_model_structure.attributes.polygon import Polygon
@ -37,19 +38,20 @@ class CityGmlLod1(CityGmlBase):
def _solid(cls, city_object_member):
try:
solid_points = [
CityGmlBase._solid_points(CityGmlBase._remove_last_point(s['Polygon']['exterior']['LinearRing']['posList']
['#text']))
GeometryHelper.points_from_string(GeometryHelper.remove_last_point_from_string(
s['Polygon']['exterior']['LinearRing']['posList']['#text']))
for s in city_object_member['lod1Solid']['Solid']['exterior']['CompositeSurface']['surfaceMember']]
except TypeError:
solid_points = [
CityGmlBase._solid_points(CityGmlBase._remove_last_point(s['Polygon']['exterior']['LinearRing']['posList']))
GeometryHelper.points_from_string(GeometryHelper.remove_last_point_from_string(
s['Polygon']['exterior']['LinearRing']['posList']))
for s in city_object_member['lod1Solid']['Solid']['exterior']['CompositeSurface']['surfaceMember']]
return [Surface(Polygon(sp), Polygon(sp)) for sp in solid_points]
@classmethod
def _multi_surface(cls, city_object_member):
solid_points = [CityGmlBase._solid_points(CityGmlBase._remove_last_point(s['Polygon']['exterior']['LinearRing']
['posList']))
solid_points = [GeometryHelper.points_from_string(GeometryHelper.remove_last_point_from_string(
s['Polygon']['exterior']['LinearRing']['posList']))
for s in city_object_member['Building']['lod1MultiSurface']['MultiSurface']['surfaceMember']]
return [Surface(Polygon(sp), Polygon(sp)) for sp in solid_points]

View File

@ -60,11 +60,19 @@ class CityGmlLod2(CityGmlBase):
@classmethod
def _add_member_surface(cls, member, surface_type):
if '@srsDimension' in member['Polygon']['exterior']['LinearRing']['posList']:
pos_name = 'posList'
if pos_name not in member['Polygon']['exterior']['LinearRing']:
pos_name = 'pos'
if '@srsDimension' in member['Polygon']['exterior']['LinearRing'][pos_name]:
gml_points = member['Polygon']['exterior']['LinearRing']['posList']["#text"]
else:
gml_points = member['Polygon']['exterior']['LinearRing']['posList']
solid_points = cls._solid_points(cls._remove_last_point(gml_points))
gml_points = member['Polygon']['exterior']['LinearRing'][pos_name]
if pos_name == 'pos':
gml_points_string = ''
for gml_point in gml_points:
gml_points_string = f'{gml_points_string} {gml_point}'
gml_points = gml_points_string.lstrip(' ')
solid_points = GeometryHelper.points_from_string(GeometryHelper.remove_last_point_from_string(gml_points))
polygon = Polygon(solid_points)
return Surface(polygon, polygon, surface_type=GeometryHelper.gml_surface_to_libs(surface_type))

149
imports/geometry/geojson.py Normal file
View File

@ -0,0 +1,149 @@
"""
Geojson module parses geojson files and import the geometry into the city model structure
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guillermo Gutierrez Guillermo.GutierrezMorote@concordia.ca
"""
import json
import trimesh.creation
import numpy as np
from pyproj import Transformer
from shapely.geometry import Polygon as ShapelyPolygon
import helpers.constants as cte
from imports.geometry.helpers.geometry_helper import GeometryHelper
from city_model_structure.attributes.polygon import Polygon
from city_model_structure.building import Building
from city_model_structure.building_demand.surface import Surface
from city_model_structure.city import City
class Geojson:
"""
Geojson class
"""
X = 0
Y = 1
def __init__(self, path, extrusion_height_field=None, year_of_construction_field=None, function_field=None):
# todo: destination epsg should change according actual the location
self._transformer = Transformer.from_crs('epsg:4326', 'epsg:26911')
self._min_x = cte.MAX_FLOAT
self._min_y = cte.MAX_FLOAT
self._max_x = cte.MIN_FLOAT
self._max_y = cte.MIN_FLOAT
self._max_z = 0
self._city = None
self._extrusion_height_field = extrusion_height_field
self._year_of_construction_field = year_of_construction_field
self._function_field = function_field
with open(path) as json_file:
self._geojson = json.loads(json_file.read())
def _save_bounds(self, x, y):
if x > self._max_x:
self._max_x = x
if x < self._min_x:
self._min_x = x
if y > self._max_y:
self._max_y = y
if y < self._min_y:
self._min_y = y
@staticmethod
def _create_buildings_lod0(name, year_of_construction, function, surfaces_coordinates):
surfaces = []
buildings = []
for zone, surface_coordinates in enumerate(surfaces_coordinates):
points = GeometryHelper.points_from_string(GeometryHelper.remove_last_point_from_string(surface_coordinates))
polygon = Polygon(points)
surfaces.append(Surface(polygon, polygon))
buildings.append(Building(f'{name}_zone_{zone}', surfaces, year_of_construction, function))
return buildings
@staticmethod
def _create_buildings_lod1(name, year_of_construction, function, height, surface_coordinates):
lod0_buildings = Geojson._create_buildings_lod0(name, year_of_construction, function, surface_coordinates)
surfaces = []
buildings = []
for zone, lod0_building in enumerate(lod0_buildings):
for surface in lod0_building.surfaces:
shapely_polygon = ShapelyPolygon(surface.solid_polygon.coordinates)
if not shapely_polygon.is_valid:
print(surface.solid_polygon.area)
print('error?', name, surface_coordinates)
continue
mesh = trimesh.creation.extrude_polygon(shapely_polygon, height)
for face in mesh.faces:
points = []
for vertex_index in face:
points.append(mesh.vertices[vertex_index])
polygon = Polygon(points)
surface = Surface(polygon, polygon)
surfaces.append(surface)
buildings.append(Building(f'{name}_zone_{zone}', surfaces, year_of_construction, function))
return buildings
def _get_polygons(self, polygons, coordinates):
if type(coordinates[0][self.X]) != float:
polygons = []
for element in coordinates:
polygons = self._get_polygons(polygons, element)
return polygons
else:
transformed_coordinates = ''
for coordinate in coordinates:
transformed = self._transformer.transform(coordinate[self.Y], coordinate[self.X])
self._save_bounds(transformed[self.X], transformed[self.Y])
transformed_coordinates = f'{transformed_coordinates} {transformed[self.X]} {transformed[self.Y]} 0.0'
polygons.append(transformed_coordinates.lstrip(' '))
return polygons
@property
def city(self) -> City:
"""
Get city out of a Geojson file
"""
if self._city is None:
buildings = []
building_id = 0
for feature in self._geojson['features']:
extrusion_height = 0
if self._extrusion_height_field is not None:
extrusion_height = float(feature['properties'][self._extrusion_height_field])
year_of_construction = None
if self._year_of_construction_field is not None:
year_of_construction = int(feature['properties'][self._year_of_construction_field])
function = None
if self._function_field is not None:
function = feature['properties'][self._function_field]
geometry = feature['geometry']
if 'id' in feature:
building_name = feature['id']
else:
building_name = f'building_{building_id}'
building_id += 1
polygons = []
for part, coordinates in enumerate(geometry['coordinates']):
polygons = self._get_polygons(polygons, coordinates)
for zone, polygon in enumerate(polygons):
if extrusion_height == 0:
buildings = buildings + Geojson._create_buildings_lod0(f'{building_name}_part_{part}_zone{zone}',
year_of_construction,
function,
[polygon])
else:
if self._max_z < extrusion_height:
self._max_z = extrusion_height
buildings = buildings + Geojson._create_buildings_lod1(f'{building_name}_part_{part}',
year_of_construction,
function,
extrusion_height,
[polygon])
self._city = City([self._min_x, self._min_y, 0.0], [self._max_x, self._max_y, self._max_z], 'epsg:26911')
for building in buildings:
self._city.add_city_object(building)
return self._city

115
imports/geometry/gpandas.py Normal file
View File

@ -0,0 +1,115 @@
"""
gpandas module parses geopandas input table and import the geometry into the city model structure
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder: Milad Aghamohamadnia --- milad.aghamohamadnia@concordia.ca
"""
import trimesh
import trimesh.exchange.load
import trimesh.geometry
import trimesh.creation
import trimesh.repair
from shapely.geometry import Point
from shapely.geometry import Polygon as ShapelyPoly
from trimesh import Scene
from city_model_structure.attributes.polygon import Polygon
from city_model_structure.building import Building
from city_model_structure.building_demand.surface import Surface
from city_model_structure.city import City
import helpers.constants as cte
class GPandas:
"""
GeoPandas class
"""
def __init__(self, dataframe, srs_name='EPSG:26911'):
"""_summary_
Arguments:
dataframe {Geopandas.Dataframe} -- input geometry data in geopandas table
Keyword Arguments:
srs_name {str} -- coordinate system of coordinate system (default: {'EPSG:26911'})
"""
self._srs_name = srs_name
self._city = None
self._scene = dataframe
self._scene = self._scene.to_crs(self._srs_name)
min_x, min_y, max_x, max_y = self._scene.total_bounds
self._lower_corner = [min_x, min_y, 0]
self._upper_corner = [max_x, max_y, 0]
@property
def scene(self) -> Scene:
"""
Get GeoPandas scene
"""
return self._scene
@property
def city(self) -> City:
"""
Get city out of a GeoPandas Table
"""
if self._city is None:
self._city = City(self._lower_corner, self._upper_corner, self._srs_name)
for scene_index, bldg in self._scene.iterrows():
geometry = bldg.geom
polygon = ShapelyPoly(geometry['coordinates'][0])
height = float(bldg['height'])
building_mesh = trimesh.creation.extrude_polygon(polygon, height)
trimesh.repair.fill_holes(building_mesh)
trimesh.repair.fix_winding(building_mesh)
year_of_construction = int(bldg['year_built'])
name = str(scene_index)
lod = 1
if year_of_construction > 2000:
function = cte.RESIDENTIAL
else:
function = cte.INDUSTRY
surfaces = []
for face_index, face in enumerate(building_mesh.faces):
points = []
for vertex_index in face:
points.append(building_mesh.vertices[vertex_index])
solid_polygon = Polygon(points)
perimeter_polygon = solid_polygon
surface = Surface(solid_polygon, perimeter_polygon)
surfaces.append(surface)
building = Building(name, surfaces, year_of_construction, function, terrains=None)
self._city.add_city_object(building)
self._city.level_of_detail.geometry = lod
return self._city
@staticmethod
def resize_polygon(poly, factor=0.10, expand=False) -> ShapelyPoly:
"""
returns the shapely polygon which is smaller or bigger by passed factor.
Arguments:
poly {shapely.geometry.Polygon} -- an input geometry in shapely polygon format
Keyword Arguments:
factor {float} -- factor of expansion (default: {0.10})
expand {bool} -- If expand = True , then it returns bigger polygon, else smaller (default: {False})
Returns:
{shapely.geometry.Polygon} -- output geometry in shapely polygon format
"""
xs = list(poly.exterior.coords.xy[0])
ys = list(poly.exterior.coords.xy[1])
x_center = 0.5 * min(xs) + 0.5 * max(xs)
y_center = 0.5 * min(ys) + 0.5 * max(ys)
min_corner = Point(min(xs), min(ys))
center = Point(x_center, y_center)
shrink_distance = center.distance(min_corner) * factor
if expand:
poly_resized = poly.buffer(shrink_distance) # expand
else:
poly_resized = poly.buffer(-shrink_distance) # shrink
return poly_resized

View File

@ -6,6 +6,7 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import helpers.constants as cte
import numpy as np
class GeometryHelper:
@ -307,3 +308,15 @@ class GeometryHelper:
if surface == 'GroundSurface':
return 'Ground'
return 'Roof'
@staticmethod
def points_from_string(coordinates) -> np.ndarray:
points = np.fromstring(coordinates, dtype=float, sep=' ')
points = GeometryHelper.to_points_matrix(points)
return points
@staticmethod
def remove_last_point_from_string(points):
array = points.split(' ')
res = " "
return res.join(array[0:len(array) - 3])

View File

@ -77,6 +77,7 @@ class Obj:
perimeter_polygon = solid_polygon
surface = Surface(solid_polygon, perimeter_polygon)
surfaces.append(surface)
building = Building(name, lod, surfaces, year_of_construction, function, self._lower_corner, terrains=None)
building = Building(name, surfaces, year_of_construction, function, terrains=None)
self._city.add_city_object(building)
self._city.level_of_detail.geometry = lod
return self._city

View File

@ -101,7 +101,7 @@ class Rhino:
if face is None:
break
hub_surfaces = hub_surfaces + self._add_face(face)
building = Building(name, 3, hub_surfaces, 'unknown', 'unknown', (self._min_x, self._min_y, self._min_z), [])
building = Building(name, hub_surfaces, 'unknown', 'unknown', [])
city_objects.append(building)
lower_corner = (self._min_x, self._min_y, self._min_z)
upper_corner = (self._max_x, self._max_y, self._max_z)
@ -133,4 +133,5 @@ class Rhino:
for building in buildings:
city.add_city_object(building)
city.level_of_detail.geometry = 3
return city

View File

@ -5,20 +5,32 @@ Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
import geopandas
from city_model_structure.city import City
from imports.geometry.citygml import CityGml
from imports.geometry.obj import Obj
from imports.geometry.osm_subway import OsmSubway
from imports.geometry.rhino import Rhino
from imports.geometry.gpandas import GPandas
from imports.geometry.geojson import Geojson
class GeometryFactory:
"""
GeometryFactory class
"""
def __init__(self, file_type, path):
def __init__(self, file_type,
path=None,
data_frame=None,
height_field=None,
year_of_construction_field=None,
function_field=None):
self._file_type = '_' + file_type.lower()
self._path = path
self._data_frame = data_frame
self._height_field = height_field
self._year_of_construction_field = year_of_construction_field
self._function_field = function_field
@property
def _citygml(self) -> City:
@ -26,7 +38,7 @@ class GeometryFactory:
Enrich the city by using CityGML information as data source
:return: City
"""
return CityGml(self._path).city
return CityGml(self._path, self._height_field, self._year_of_construction_field, self._function_field).city
@property
def _obj(self) -> City:
@ -36,6 +48,24 @@ class GeometryFactory:
"""
return Obj(self._path).city
@property
def _gpandas(self) -> City:
"""
Enrich the city by using GeoPandas information as data source
:return: City
"""
if self._data_frame is None:
self._data_frame = geopandas.read_file(self._path)
return GPandas(self._data_frame).city
@property
def _geojson(self) -> City:
"""
Enrich the city by using Geojson information as data source
:return: City
"""
return Geojson(self._path, self._height_field, self._year_of_construction_field, self._function_field).city
@property
def _osm_subway(self) -> City:
"""
@ -66,4 +96,4 @@ class GeometryFactory:
Enrich the city given to the class using the class given handler
:return: City
"""
return CityGml(self._path).city
return Geojson(self._path, self._height_field, self._year_of_construction_field, self._function_field).city

View File

@ -1,57 +0,0 @@
"""
Schedules retrieve the specific usage schedules module for the given standard
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import pandas as pd
from imports.schedules.helpers.schedules_helper import SchedulesHelper
from city_model_structure.attributes.schedule import Schedule
import helpers.constants as cte
class ComnetSchedules:
"""
Comnet based schedules
"""
def __init__(self, city, base_path):
self._city = city
self._comnet_schedules_path = base_path / 'comnet_archetypes.xlsx'
xls = pd.ExcelFile(self._comnet_schedules_path)
for building in city.buildings:
for usage_zone in building.usage_zones:
schedules = []
usage_schedules = pd.read_excel(xls,
sheet_name=SchedulesHelper.comnet_from_usage(usage_zone.name),
skiprows=[0, 1, 2, 3], nrows=39, usecols="A:AA")
number_of_schedule_types = 13
schedules_per_schedule_type = 3
day_types = dict({'week_day': 0, 'saturday': 1, 'sunday': 2})
for schedule_types in range(0, number_of_schedule_types):
name = ''
data_type = ''
for schedule_day in range(0, schedules_per_schedule_type):
schedule = Schedule()
schedule.time_step = cte.HOUR
schedule.time_range = cte.DAY
row_cells = usage_schedules.iloc[schedules_per_schedule_type*schedule_types + schedule_day]
if schedule_day == day_types['week_day']:
name = row_cells[0]
data_type = row_cells[1]
schedule.day_types = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY]
elif schedule_day == day_types['saturday']:
schedule.day_types = [cte.SATURDAY]
else:
schedule.day_types = [cte.SUNDAY]
schedule.type = name
schedule.data_type = SchedulesHelper.data_type_from_comnet(data_type)
if schedule.data_type == cte.ANY_NUMBER:
values = []
for cell in row_cells[schedules_per_schedule_type:].to_numpy():
values.append((float(cell) - 32.) * 5 / 9)
schedule.values = values
else:
schedule.values = row_cells[schedules_per_schedule_type:].to_numpy()
schedules.append(schedule)
usage_zone.schedules = schedules

View File

@ -1,149 +0,0 @@
"""
Building test
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez Morote Guillermo.GutierrezMorote@concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import pandas as pd
import parseidf
import xmltodict
from imports.schedules.helpers.schedules_helper import SchedulesHelper
from city_model_structure.attributes.schedule import Schedule
from city_model_structure.building_demand.occupancy import Occupancy
from city_model_structure.building_demand.lighting import Lighting
from city_model_structure.building_demand.thermal_control import ThermalControl
import helpers.constants as cte
class DoeIdf:
"""
Idf factory to import schedules into the data model
"""
# todo: shouldn't this be in the schedule helper class????
idf_schedule_to_standard_schedule = {'BLDG_LIGHT_SCH': cte.LIGHTING,
'BLDG_OCC_SCH_wo_SB': cte.OCCUPANCY,
'BLDG_EQUIP_SCH': cte.EQUIPMENT,
'ACTIVITY_SCH': cte.ACTIVITY,
'INFIL_QUARTER_ON_SCH': cte.INFILTRATION}
# todo: @Guille -> in idf the types can be written in capital letters or low case, but both should be accepted.
# How is that solved?? Of course not like this
idf_data_type_to_standard_data_type = {'Fraction': cte.FRACTION,
'fraction': cte.FRACTION,
'Any Number': cte.ANY_NUMBER,
'ON/OFF': cte.ON_OFF,
'On/Off': cte.ON_OFF,
'Temperature': cte.TEMPERATURE,
'Humidity': cte.HUMIDITY,
'Control Type': cte.CONTROL_TYPE}
_SCHEDULE_COMPACT_TYPE = 'SCHEDULE:COMPACT'
_SCHEDULE_TYPE_NAME = 1
_SCHEDULE_TYPE_DATA_TYPE = 2
def __init__(self, city, base_path, doe_idf_file):
self._hours = []
panda_hours = pd.timedelta_range(0, periods=24, freq='H')
for _, hour in enumerate(panda_hours):
self._hours.append(str(hour).replace('0 days ', '').replace(':00:00', ':00'))
self._city = city
path = str(base_path / doe_idf_file)
with open(path) as xml:
self._schedule_library = xmltodict.parse(xml.read())
for building in self._city.buildings:
for internal_zone in building.internal_zones:
for usage_zone in internal_zone.usage_zones:
for schedule_archetype in self._schedule_library['archetypes']['archetypes']:
function = schedule_archetype['@building_type']
if SchedulesHelper.usage_from_function(function) == usage_zone.name:
self._idf_schedules_path = (base_path / schedule_archetype['idf']['path']).resolve()
with open(self._idf_schedules_path, 'r') as file:
idf = parseidf.parse(file.read())
self._load_schedule(idf, usage_zone)
break
def _load_schedule(self, idf, usage_zone):
schedules_day = {}
schedules = []
for compact_schedule in idf[self._SCHEDULE_COMPACT_TYPE]:
schedule = Schedule()
schedule.time_step = cte.HOUR
schedule.time_range = cte.DAY
if compact_schedule[self._SCHEDULE_TYPE_NAME] in self.idf_schedule_to_standard_schedule:
schedule.type = self.idf_schedule_to_standard_schedule[compact_schedule[self._SCHEDULE_TYPE_NAME]]
schedule.data_type = self.idf_data_type_to_standard_data_type[compact_schedule[self._SCHEDULE_TYPE_DATA_TYPE]]
else:
continue
days_index = []
days_schedules = []
for position, elements in enumerate(compact_schedule):
element_title = elements.title().replace('For: ', '')
if elements.title() != element_title:
days_index.append(position)
# store a cleaned version of the compact schedule
days_schedules.append(element_title)
days_index.append(len(days_schedules))
# save schedule
values = []
for i, day_index in enumerate(days_index):
if day_index == len(days_schedules):
break
schedules_day[f'{days_schedules[day_index]}'] = []
hour_index = 0
for hours_values in range(day_index + 1, days_index[i + 1] - 1, 2):
# Create 24h sequence
for index, hour in enumerate(self._hours[hour_index:]):
hour_formatted = days_schedules[hours_values].replace("Until: ", "")
if len(hour_formatted) == 4:
hour_formatted = f'0{hour_formatted}'
if hour == hour_formatted:
hour_index += index
break
entry = days_schedules[hours_values + 1]
schedules_day[f'{days_schedules[day_index]}'].append(entry)
for entry in schedules_day[f'{days_schedules[day_index]}']:
values.append(entry)
schedule.values = values
if 'Weekdays' in days_schedules[day_index]:
schedule.day_types = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY]
elif 'Alldays' in days_schedules[day_index]:
schedule.day_types = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY, cte.SATURDAY,
cte.SUNDAY]
elif 'Weekends' in days_schedules[day_index]:
# Weekends schedule present so let's re set the values
schedule.day_types = [cte.SATURDAY, cte.SUNDAY]
elif 'Saturday' in days_schedules[day_index]:
schedule.day_types = [cte.SATURDAY]
elif 'Sunday' in days_schedules[day_index]:
schedule.day_types = [cte.SUNDAY]
else:
continue
schedules.append(schedule)
for schedule in schedules:
if schedule.type == cte.OCCUPANCY:
if usage_zone.occupancy is None:
usage_zone.occupancy = Occupancy()
usage_zone.occupancy.occupancy_schedules = [schedule]
elif schedule.type == cte.LIGHTING:
if usage_zone.lighting is None:
usage_zone.lighting = Lighting()
usage_zone.lighting.schedules = [schedule]
elif schedule.type == cte.HVAC_AVAILABILITY:
if usage_zone.thermal_control is None:
usage_zone.thermal_control = ThermalControl()
usage_zone.thermal_control.hvac_availability_schedules = [schedule]

View File

@ -1,39 +0,0 @@
"""
SchedulesFactory retrieve the specific schedules module for the given standard
This factory can only be called after calling the usage factory so the usage zones are created.
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
from pathlib import Path
from imports.schedules.doe_idf import DoeIdf
class SchedulesFactory:
"""
SchedulesFactor class
"""
def __init__(self, handler, city, base_path=Path(Path(__file__).parent.parent / 'data/schedules')):
self._handler = '_' + handler.lower().replace(' ', '_')
self._city = city
self._base_path = base_path
for building in city.buildings:
for internal_zone in building.internal_zones:
if len(internal_zone.usage_zones) == 0:
raise Exception('It seems that the schedule factory is being called before the usage factory. '
'Please ensure that the usage factory is called first as the usage zones must be '
'firstly generated.')
def _doe_idf(self):
"""
Enrich the city by using DOE IDF schedules as data source
"""
DoeIdf(self._city, self._base_path, 'doe_idf.xml')
def enrich(self):
"""
Enrich the city given to the class using the given schedule handler
:return: None
"""
getattr(self, self._handler, lambda: None)()

View File

@ -14,8 +14,8 @@ import helpers.constants as cte
from helpers.configuration_helper import ConfigurationHelper as ch
from imports.geometry.helpers.geometry_helper import GeometryHelper
from imports.usage.helpers.usage_helper import UsageHelper
from imports.schedules.helpers.schedules_helper import SchedulesHelper
from city_model_structure.building_demand.usage import Usage
from imports.usage.helpers.schedules_helper import SchedulesHelper
from city_model_structure.building_demand.usage_zone import UsageZone
from city_model_structure.building_demand.lighting import Lighting
from city_model_structure.building_demand.occupancy import Occupancy
from city_model_structure.building_demand.appliances import Appliances
@ -42,8 +42,8 @@ class ComnetUsageParameters:
"""
number_usage_types = 33
xl_file = pd.ExcelFile(self._base_path)
file_data = pd.read_excel(xl_file, sheet_name="Modeling Data", skiprows=[0, 1, 2],
nrows=number_usage_types, usecols="A:AB")
file_data = pd.read_excel(xl_file, sheet_name="Modeling Data", usecols="A:AB", skiprows=[0, 1, 2],
nrows=number_usage_types)
lighting_data = {}
plug_loads_data = {}
@ -74,7 +74,7 @@ class ComnetUsageParameters:
@staticmethod
def _parse_usage_type(comnet_usage, data, schedules_data):
_usage_zone = Usage()
_usage_zone = UsageZone()
# lighting
_lighting = Lighting()
@ -109,8 +109,8 @@ class ComnetUsageParameters:
schedules_usage = UsageHelper.schedules_key(data['schedules_key'][comnet_usage][0])
_extracted_data = pd.read_excel(schedules_data, sheet_name=schedules_usage,
skiprows=[0, 1, 2, 3], nrows=39, usecols="A:AA")
_extracted_data = pd.read_excel(schedules_data, sheet_name=schedules_usage, usecols="A:AA", skiprows=[0, 1, 2, 3],
nrows=39)
schedules = []
number_of_schedule_types = 13
schedules_per_schedule_type = 3
@ -213,8 +213,8 @@ class ComnetUsageParameters:
if internal_zone.volume <= 0:
raise Exception('Internal zone volume is zero, ACH cannot be calculated')
volume_per_area = internal_zone.volume / internal_zone.area
usage_zone = Usage()
usage_zone.name = usage
usage_zone = UsageZone()
usage_zone.usage = usage
self._assign_values_usage_zone(usage_zone, archetype_usage, volume_per_area)
usage_zone.percentage = 1
self._calculate_reduced_values_from_extended_library(usage_zone, archetype_usage)

View File

@ -26,12 +26,14 @@ class UsageFactory:
"""
Enrich the city with HFT usage library
"""
self._city.level_of_detail.usage = 2
return HftUsageParameters(self._city, self._base_path).enrich_buildings()
def _comnet(self):
"""
Enrich the city with COMNET usage library
"""
self._city.level_of_detail.usage = 2
return ComnetUsageParameters(self._city, self._base_path).enrich_buildings()
def enrich(self):

View File

@ -16,3 +16,6 @@ rhino3dm==7.7.0
scipy
PyYAML
pyecore==0.12.2
shapely
geopandas
triangle

View File

@ -23,7 +23,7 @@ class TestCityMerge(TestCase):
def _get_citygml(self, file):
file_path = (self._example_path / file).resolve()
city = GeometryFactory('citygml', file_path).city
city = GeometryFactory('citygml', path=file_path).city
self.assertIsNotNone(city, 'city is none')
return city

View File

@ -26,8 +26,9 @@ class TestConstructionFactory(TestCase):
def _get_citygml(self, file):
file_path = (self._example_path / file).resolve()
self._city = GeometryFactory('citygml', file_path).city
self._city = GeometryFactory('citygml', path=file_path).city
self.assertIsNotNone(self._city, 'city is none')
self.assertIsNotNone(self._city.level_of_detail.geometry, 'wrong construction level of detail')
return self._city
@staticmethod
@ -70,7 +71,6 @@ class TestConstructionFactory(TestCase):
def _check_buildings(self, city):
for building in city.buildings:
self.assertIsNotNone(building.name, 'building name is none')
self.assertIsNotNone(building.lod, 'building lod is none')
self.assertIsNotNone(building.type, 'building type is none')
self.assertIsNotNone(building.volume, 'building volume is none')
self.assertIsNotNone(building.detailed_polyhedron, 'building detailed polyhedron is none')
@ -193,3 +193,12 @@ class TestConstructionFactory(TestCase):
self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
self._check_thermal_openings(thermal_boundary)
self._check_surfaces(thermal_boundary)
def test_archetype_not_found(self):
file = 'pluto_building.gml'
city = self._get_citygml(file)
for building in city.buildings:
building.year_of_construction = 1990
building.function = 'office'
ConstructionFactory('nrel', city).enrich()

View File

@ -1,57 +0,0 @@
"""
Building test
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez Morote Guillermo.GutierrezMorote@concordia.ca
"""
from pathlib import Path
from unittest import TestCase
from imports.geometry_factory import GeometryFactory
from imports.usage_factory import UsageFactory
from imports.construction_factory import ConstructionFactory
from exports.exports_factory import ExportsFactory
class TestBuildings(TestCase):
"""
TestBuilding TestCase 1
"""
def setUp(self) -> None:
"""
Test setup
:return: None
"""
self._city_gml = None
self._example_path = (Path(__file__).parent / 'tests_data').resolve()
def test_doe_idf(self):
city_file = "../unittests/tests_data/one_building_in_kelowna.gml"
output_path = Path('../unittests/tests_outputs/').resolve()
city = GeometryFactory('citygml', city_file).city
for building in city.buildings:
building.year_of_construction = 2006
ConstructionFactory('nrel', city).enrich()
UsageFactory('comnet', city).enrich()
ExportsFactory('idf', city, output_path).export()
self.assertEqual(1, len(city.buildings))
for building in city.buildings:
for internal_zone in building.internal_zones:
self.assertTrue(len(internal_zone.usage_zones) > 0)
for usage_zone in internal_zone.usage_zones:
self.assertIsNot(len(usage_zone.occupancy.occupancy_schedules), 0, 'no occupancy schedules defined')
for schedule in usage_zone.occupancy.occupancy_schedules:
self.assertIsNotNone(schedule.type)
self.assertIsNotNone(schedule.values)
self.assertIsNotNone(schedule.data_type)
self.assertIsNotNone(schedule.time_step)
self.assertIsNotNone(schedule.time_range)
self.assertIsNotNone(schedule.day_types)
self.assertIsNot(len(usage_zone.lighting.schedules), 0, 'no lighting schedules defined')
for schedule in usage_zone.lighting.schedules:
self.assertIsNotNone(schedule.type)
self.assertIsNotNone(schedule.values)
self.assertIsNotNone(schedule.data_type)
self.assertIsNotNone(schedule.time_step)
self.assertIsNotNone(schedule.time_range)
self.assertIsNotNone(schedule.day_types)

View File

@ -25,7 +25,7 @@ class TestEnergySystemsFactory(TestCase):
"""
city_file = "../unittests/tests_data/C40_Final.gml"
self._output_path = "../unittests/tests_data/as_user_output.csv"
self._city = GeometryFactory('citygml', city_file).city
self._city = GeometryFactory('citygml', path=city_file).city
EnergySystemsFactory('air source hp', self._city).enrich()
def test_air_source_heat_pump_import(self):

View File

@ -26,7 +26,7 @@ class TestEnergySystemsFactory(TestCase):
"""
city_file = "../unittests/tests_data/C40_Final.gml"
self._output_path = "../unittests/tests_data/w2w_user_output.csv"
self._city = GeometryFactory('citygml', city_file).city
self._city = GeometryFactory('citygml', path=city_file).city
EnergySystemsFactory('water to water hp', self._city).enrich()
def test_water_to_water_heat_pump_import(self):
@ -48,7 +48,18 @@ class TestEnergySystemsFactory(TestCase):
'FuelPrice': 0.12,
'FuelEF': 1887,
'FuelDensity': 0.717,
'HPSupTemp': 60
'HPSupTemp': 60,
'b1': 10,
'b2': 10,
'b3': 10,
'b4': 10,
'b5': 10,
'b6': 10,
'b7': 10,
'b8': 10,
'b9': 10,
'b10': 10,
'b11': 10
}
EnergySystemsExportFactory(self._city, user_input, 'ClimateMaster 156 kW', self._output_path).export('water')

View File

@ -27,7 +27,7 @@ class TestGeometryFactory(TestCase):
def _get_citygml(self, file):
file_path = (self._example_path / file).resolve()
self._city = GeometryFactory('citygml', file_path).city
self._city = GeometryFactory('citygml', path=file_path).city
self.assertIsNotNone(self._city, 'city is none')
return self._city
@ -93,9 +93,7 @@ class TestGeometryFactory(TestCase):
_construction_keys = ['nrel']
_usage_keys = ['comnet', 'hft']
for construction_key in _construction_keys:
print('construction key: ', construction_key)
for usage_key in _usage_keys:
print('usage key: ', usage_key)
# construction factory called first
city = self._get_citygml(file)
for building in city.buildings:

View File

@ -14,6 +14,7 @@ from imports.geometry.helpers.geometry_helper import GeometryHelper
from imports.construction_factory import ConstructionFactory
from imports.usage_factory import UsageFactory
from exports.exports_factory import ExportsFactory
from exports.energy_building_exports_factory import EnergyBuildingsExportsFactory
import helpers.constants as cte
from city_model_structure.city import City
@ -34,7 +35,7 @@ class TestExports(TestCase):
def _get_citygml(self, file):
file_path = (self._example_path / file).resolve()
self._city = GeometryFactory('citygml', file_path).city
self._city = GeometryFactory('citygml', path=file_path).city
self.assertIsNotNone(self._city, 'city is none')
return self._city
@ -102,8 +103,9 @@ class TestExports(TestCase):
ConstructionFactory('nrel', city).enrich()
UsageFactory('comnet', city).enrich()
try:
ExportsFactory('idf', city, self._output_path).export()
ExportsFactory('idf', city, self._output_path, target_buildings=['gml_1066158', 'gml_1066159']).export()
EnergyBuildingsExportsFactory('idf', city, self._output_path).export()
EnergyBuildingsExportsFactory('idf', city, self._output_path,
target_buildings=['gml_1066158', 'gml_1066159']).export()
except Exception:
self.fail("Idf ExportsFactory raised ExceptionType unexpectedly!")

View File

@ -9,8 +9,9 @@ from unittest import TestCase
from numpy import inf
from imports.geometry_factory import GeometryFactory
import exports.exports_factory
from imports.construction_factory import ConstructionFactory
from imports.geometry_factory import GeometryFactory
class TestGeometryFactory(TestCase):
@ -25,36 +26,26 @@ class TestGeometryFactory(TestCase):
"""
self._city = None
self._example_path = (Path(__file__).parent / 'tests_data').resolve()
self._output_path = (Path(__file__).parent / 'tests_outputs').resolve()
def _get_citygml(self, file):
def _get_city(self, file, file_type, height_field=None, year_of_construction_field=None, function_field=None):
file_path = (self._example_path / file).resolve()
self._city = GeometryFactory('citygml', file_path).city
self.assertIsNotNone(self._city, 'city is none')
return self._city
def _get_obj(self, file):
# todo: solve the incongruities between city and city_debug
file_path = (self._example_path / file).resolve()
self._city = GeometryFactory('obj', file_path).city
self.assertIsNotNone(self._city, 'city is none')
return self._city
def _get_rhino(self, file):
file_path = (self._example_path / file).resolve()
self._city = GeometryFactory('rhino', file_path).city
self._city = GeometryFactory(file_type,
path=file_path,
height_field=height_field,
year_of_construction_field=year_of_construction_field,
function_field=function_field).city
self.assertIsNotNone(self._city, 'city is none')
return self._city
def _check_buildings(self, city):
for building in city.buildings:
self.assertIsNotNone(building.name, 'building name is none')
self.assertIsNotNone(building.lod, 'building lod is none')
self.assertIsNotNone(building.type, 'building type is none')
self.assertIsNotNone(building.volume, 'building volume is none')
self.assertIsNotNone(building.detailed_polyhedron, 'building detailed polyhedron is none')
self.assertIsNotNone(building.simplified_polyhedron, 'building simplified polyhedron is none')
self.assertIsNotNone(building.surfaces, 'building surfaces is none')
self.assertIsNotNone(building.centroid, 'building centroid is none')
self.assertIsNotNone(building.max_height, 'building max_height is none')
self.assertEqual(len(building.external_temperature), 0, 'building external temperature is calculated')
self.assertEqual(len(building.global_horizontal), 0, 'building global horizontal is calculated')
@ -73,8 +64,6 @@ class TestGeometryFactory(TestCase):
self.assertIsNone(building.basement_heated, 'building basement_heated is not none')
self.assertIsNone(building.attic_heated, 'building attic_heated is not none')
self.assertIsNone(building.terrains, 'building terrains is not none')
self.assertIsNotNone(building.year_of_construction, 'building year_of_construction is none')
self.assertIsNotNone(building.function, 'building function is none')
self.assertIsNone(building.average_storey_height, 'building average_storey_height is not none')
self.assertIsNone(building.storeys_above_ground, 'building storeys_above_ground is not none')
self.assertEqual(len(building.heating), 0, 'building heating is not none')
@ -111,8 +100,8 @@ class TestGeometryFactory(TestCase):
Test city objects in the city
:return: None
"""
file = 'one_building_in_kelowna.gml'
city = self._get_citygml(file)
file = 'FZK_Haus_LoD_2.gml'
city = self._get_city(file, 'citygml', year_of_construction_field='yearOfConstruction')
self.assertTrue(len(city.buildings) == 1)
self._check_buildings(city)
for building in city.buildings:
@ -120,13 +109,12 @@ class TestGeometryFactory(TestCase):
building.year_of_construction = 2006
city = ConstructionFactory('nrel', city).enrich()
# rhino
def test_import_rhino(self):
"""
Test rhino import
"""
file = 'dompark.3dm'
city = self._get_rhino(file)
city = self._get_city(file, 'rhino')
self.assertIsNotNone(city, 'city is none')
self.assertTrue(len(city.buildings) == 36)
i = 0
@ -134,28 +122,40 @@ class TestGeometryFactory(TestCase):
self.assertIsNot(building.volume, inf, 'open volume')
i += 1
# obj
def test_import_obj(self):
"""
Test obj import
"""
file = 'kelowna.obj'
city = self._get_obj(file)
self.assertIsNotNone(city, 'city is none')
city = self._get_city(file, 'obj')
self.assertTrue(len(city.buildings) == 1)
self._check_buildings(city)
for building in city.buildings:
self._check_surfaces(building)
# osm
def test_subway(self):
def test_import_geopandas(self):
"""
Test subway parsing
:return:
Test geopandas import
"""
file_path = (self._example_path / 'subway.osm').resolve()
file = 'sample.geojson'
city = self._get_city(file, 'gpandas')
self.assertTrue(len(city.buildings) == 1)
self._check_buildings(city)
for building in city.buildings:
self._check_surfaces(building)
self.assertEqual(1912.0898135701814, building.volume)
self.assertEqual(146.19493345171213, building.floor_area)
city = GeometryFactory('osm_subway', file_path).city
def test_import_geojson(self):
"""
Test geojson import
"""
file = 'sample.geojson'
city = self._get_city(file, 'geojson',
height_field='citygml_me',
year_of_construction_field='ANNEE_CONS',
function_field='LIBELLE_UT')
self.assertIsNotNone(city, 'subway entrances is none')
self.assertEqual(len(city.city_objects), 20, 'Wrong number of subway entrances')
exports.exports_factory.ExportsFactory('obj', city, self._output_path).export_debug()
self.assertEqual(207, len(city.buildings), 'wrong number of buildings')
self._check_buildings(city)

View File

@ -1,5 +1,5 @@
"""
TestGeometryFactory test and validate the city model structure geometric parameters
Test greenery factory test and validate the greenery construction
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca

View File

@ -11,7 +11,7 @@ from unittest import TestCase
from imports.geometry_factory import GeometryFactory
from imports.usage_factory import UsageFactory
from imports.construction_factory import ConstructionFactory
from exports.exports_factory import ExportsFactory
from exports.energy_building_exports_factory import EnergyBuildingsExportsFactory
from city_model_structure.greenery.vegetation import Vegetation
from city_model_structure.greenery.soil import Soil
from city_model_structure.greenery.plant import Plant
@ -27,7 +27,7 @@ class GreeneryInIdf(TestCase):
city_file = "../unittests/tests_data/one_building_in_kelowna.gml"
output_path = Path('../unittests/tests_outputs/').resolve()
city = GeometryFactory('citygml', city_file).city
city = GeometryFactory('citygml', path=city_file).city
for building in city.buildings:
building.year_of_construction = 2006
ConstructionFactory('nrel', city).enrich()
@ -66,7 +66,7 @@ class GreeneryInIdf(TestCase):
if surface.type == cte.ROOF:
surface.vegetation = vegetation
_idf_2 = ExportsFactory('idf', city, output_path).export_debug()
_idf_2 = EnergyBuildingsExportsFactory('idf', city, output_path).export_debug()
_idf_2.run()
with open((output_path / f'{city.name}_out.csv').resolve()) as f:
reader = csv.reader(f, delimiter=',')
@ -80,12 +80,12 @@ class GreeneryInIdf(TestCase):
print('With greenery')
print(f'heating: {heating} MWh/yr, cooling: {cooling} MWh/yr')
city = GeometryFactory('citygml', city_file).city
city = GeometryFactory('citygml', path=city_file).city
for building in city.buildings:
building.year_of_construction = 2006
ConstructionFactory('nrel', city).enrich()
UsageFactory('comnet', city).enrich()
_idf = ExportsFactory('idf', city, output_path).export()
_idf = EnergyBuildingsExportsFactory('idf', city, output_path).export()
_idf.run()
with open((output_path / f'{city.name}_out.csv').resolve()) as f:
reader = csv.reader(f, delimiter=',')

View File

@ -0,0 +1,148 @@
"""
TestInselExports test
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from pathlib import Path
from unittest import TestCase
import pandas as pd
import helpers.constants as cte
from helpers.monthly_values import MonthlyValues
from imports.geometry_factory import GeometryFactory
from imports.construction_factory import ConstructionFactory
from imports.usage_factory import UsageFactory
from exports.energy_building_exports_factory import EnergyBuildingsExportsFactory
from imports.weather_factory import WeatherFactory
class TestExports(TestCase):
"""
TestExports class contains the unittest for export functionality
"""
def setUp(self) -> None:
"""
Test setup
:return: None
"""
self._city = None
self._complete_city = None
self._example_path = (Path(__file__).parent / 'tests_data').resolve()
self._output_path = (Path(__file__).parent / 'tests_outputs').resolve()
def _get_citygml(self, file):
file_path = (self._example_path / file).resolve()
self._city = GeometryFactory('citygml', path=file_path).city
self.assertIsNotNone(self._city, 'city is none')
return self._city
@property
def _read_sra_file(self) -> []:
path = (self._example_path / "one_building_in_kelowna_sra_SW.out").resolve()
_results = pd.read_csv(path, sep='\s+', header=0)
id_building = ''
header_building = []
_radiation = []
for column in _results.columns.values:
if id_building != column.split(':')[1]:
id_building = column.split(':')[1]
if len(header_building) > 0:
_radiation.append(pd.concat([MonthlyValues().month_hour, _results[header_building]], axis=1))
header_building = [column]
else:
header_building.append(column)
_radiation.append(pd.concat([MonthlyValues().month_hour, _results[header_building]], axis=1))
return _radiation
def _set_irradiance_surfaces(self, city):
"""
saves in building surfaces the correspondent irradiance at different time-scales depending on the mode
if building is None, it saves all buildings' surfaces in file, if building is specified, it saves only that
specific building values
:parameter city: city
:return: none
"""
for radiation in self._read_sra_file:
city_object_name = radiation.columns.values.tolist()[1].split(':')[1]
building = city.city_object(city_object_name)
for column in radiation.columns.values:
if column == cte.MONTH:
continue
header_id = column
surface_id = header_id.split(':')[2]
surface = building.surface_by_id(surface_id)
new_value = pd.DataFrame(radiation[[header_id]].to_numpy(), columns=['sra'])
surface.global_irradiance[cte.HOUR] = new_value
month_new_value = MonthlyValues().get_mean_values(new_value)
surface.global_irradiance[cte.MONTH] = month_new_value
def test_insel_monthly_energy_balance_export(self):
"""
export to Insel MonthlyEnergyBalance
"""
city = self._get_citygml('one_building_in_kelowna.gml')
WeatherFactory('epw', city, file_name='CAN_PQ_Montreal.Intl.AP.716270_CWEC.epw').enrich()
for building in city.buildings:
building.external_temperature[cte.MONTH] = MonthlyValues().\
get_mean_values(building.external_temperature[cte.HOUR][['epw']])
self._set_irradiance_surfaces(city)
for building in city.buildings:
self.assertIsNotNone(building.external_temperature[cte.MONTH], f'building {building.name} '
f'external_temperature is none')
for surface in building.surfaces:
if surface.type != 'Ground':
self.assertIsNotNone(surface.global_irradiance[cte.MONTH], f'surface in building {building.name} '
f'global_irradiance is none')
for building in city.buildings:
building.year_of_construction = 2006
if building.function is None:
building.function = 'large office'
building.attic_heated = 0
building.basement_heated = 0
ConstructionFactory('nrel', city).enrich()
UsageFactory('comnet', city).enrich()
# parameters written:
for building in city.buildings:
self.assertIsNotNone(building.volume, f'building {building.name} volume is none')
self.assertIsNotNone(building.average_storey_height, f'building {building.name} average_storey_height is none')
self.assertIsNotNone(building.storeys_above_ground, f'building {building.name} storeys_above_ground is none')
self.assertIsNotNone(building.attic_heated, f'building {building.name} attic_heated is none')
self.assertIsNotNone(building.basement_heated, f'building {building.name} basement_heated is none')
for internal_zone in building.internal_zones:
self.assertIsNotNone(internal_zone.area, f'internal zone {internal_zone.id} area is none')
for thermal_zone in internal_zone.thermal_zones:
self.assertIsNotNone(thermal_zone.indirectly_heated_area_ratio, f'thermal zone {thermal_zone.id} '
f'indirectly_heated_area_ratio is none')
self.assertIsNotNone(thermal_zone.effective_thermal_capacity, f'thermal zone {thermal_zone.id} '
f'effective_thermal_capacity is none')
self.assertIsNotNone(thermal_zone.additional_thermal_bridge_u_value, f'thermal zone {thermal_zone.id} '
f'additional_thermal_bridge_u_value '
f'is none')
self.assertIsNotNone(thermal_zone.total_floor_area, f'thermal zone {thermal_zone.id} '
f'total_floor_area is none')
for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.type)
self.assertIsNotNone(thermal_boundary.opaque_area)
self.assertIsNotNone(thermal_boundary.window_ratio)
self.assertIsNotNone(thermal_boundary.u_value)
self.assertIsNotNone(thermal_boundary.thermal_openings)
if thermal_boundary.type is not cte.GROUND:
self.assertIsNotNone(thermal_boundary.parent_surface.short_wave_reflectance)
for usage_zone in internal_zone.usage_zones:
self.assertIsNotNone(usage_zone.percentage, f'usage zone {usage_zone.usage} percentage is none')
self.assertIsNotNone(usage_zone.internal_gains, f'usage zone {usage_zone.usage} internal_gains is none')
self.assertIsNotNone(usage_zone.thermal_control, f'usage zone {usage_zone.usage} thermal_control is none')
self.assertIsNotNone(usage_zone.hours_day, f'usage zone {usage_zone.usage} hours_day is none')
self.assertIsNotNone(usage_zone.days_year, f'usage zone {usage_zone.usage} days_year is none')
self.assertIsNotNone(usage_zone.mechanical_air_change, f'usage zone {usage_zone.usage} '
f'mechanical_air_change is none')
# export files
try:
EnergyBuildingsExportsFactory('insel_monthly_energy_balance', city, self._output_path).export()
except Exception:
self.fail("Insel MonthlyEnergyBalance ExportsFactory raised ExceptionType unexpectedly!")

View File

@ -24,28 +24,28 @@ class TestLifeCycleAssessment(TestCase):
def test_fuel(self):
city_file = "../unittests/tests_data/C40_Final.gml"
city = GeometryFactory('citygml', city_file).city
city = GeometryFactory('citygml', path=city_file).city
LifeCycleAssessment('fuel', city).enrich()
for fuel in city.fuels:
self.assertTrue(len(city.fuels) > 0)
def test_vehicle(self):
city_file = "../unittests/tests_data/C40_Final.gml"
city = GeometryFactory('citygml', city_file).city
city = GeometryFactory('citygml', path=city_file).city
LifeCycleAssessment('vehicle', city).enrich()
for vehicle in city.vehicles:
self.assertTrue(len(city.vehicles) > 0)
def test_machine(self):
city_file = "../unittests/tests_data/C40_Final.gml"
city = GeometryFactory('citygml', city_file).city
city = GeometryFactory('citygml', path=city_file).city
LifeCycleAssessment('machine', city).enrich()
for machine in city.machines:
self.assertTrue(len(city.machines) > 0)
def test_material(self):
city_file = "../unittests/tests_data/C40_Final.gml"
city = GeometryFactory('citygml', city_file).city
city = GeometryFactory('citygml', path=city_file).city
LifeCycleAssessment('material', city).enrich()
for material in city.lca_materials:
self.assertTrue(len(city.lca_materials) > 0)

View File

@ -1,69 +0,0 @@
"""
TestSchedulesFactory test and validate the city model structure schedules
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from pathlib import Path
from unittest import TestCase
from imports.geometry_factory import GeometryFactory
from imports.usage_factory import UsageFactory
from imports.construction_factory import ConstructionFactory
from imports.schedules_factory import SchedulesFactory
from imports.geometry.helpers.geometry_helper import GeometryHelper
class TestSchedulesFactory(TestCase):
"""
TestSchedulesFactory TestCase
"""
def setUp(self) -> None:
"""
Configure test environment
:return:
"""
self._example_path = (Path(__file__).parent / 'tests_data').resolve()
def _get_citygml(self, file):
file_path = (self._example_path / file).resolve()
_city = GeometryFactory('citygml', file_path).city
for building in _city.buildings:
building.year_of_construction = 2006
ConstructionFactory('nrel', _city).enrich()
self.assertIsNotNone(_city, 'city is none')
for building in _city.buildings:
building.function = GeometryHelper.libs_function_from_hft(building.function)
building.year_of_construction = 2005
UsageFactory('hft', _city).enrich()
return _city
def test_doe_idf_archetypes(self):
"""
Enrich the city with doe_idf schedule archetypes and verify it
"""
file = (self._example_path / 'C40_Final.gml').resolve()
city = self._get_citygml(file)
occupancy_handler = 'doe_idf'
SchedulesFactory(occupancy_handler, city).enrich()
for building in city.buildings:
for internal_zone in building.internal_zones:
self.assertTrue(len(internal_zone.usage_zones) > 0)
for usage_zone in internal_zone.usage_zones:
self.assertIsNot(len(usage_zone.occupancy.occupancy_schedules), 0, 'no occupancy schedules defined')
for schedule in usage_zone.occupancy.occupancy_schedules:
self.assertIsNotNone(schedule.type)
self.assertIsNotNone(schedule.values)
self.assertIsNotNone(schedule.data_type)
self.assertIsNotNone(schedule.time_step)
self.assertIsNotNone(schedule.time_range)
self.assertIsNotNone(schedule.day_types)
self.assertIsNot(len(usage_zone.lighting.schedules), 0, 'no lighting schedules defined')
for schedule in usage_zone.lighting.schedules:
self.assertIsNotNone(schedule.type)
self.assertIsNotNone(schedule.values)
self.assertIsNotNone(schedule.data_type)
self.assertIsNotNone(schedule.time_step)
self.assertIsNotNone(schedule.time_range)
self.assertIsNotNone(schedule.day_types)

View File

@ -26,14 +26,13 @@ class TestUsageFactory(TestCase):
def _get_citygml(self, file):
file_path = (self._example_path / file).resolve()
self._city = GeometryFactory('citygml', file_path).city
self._city = GeometryFactory('citygml', path=file_path).city
self.assertIsNotNone(self._city, 'city is none')
return self._city
def _check_buildings(self, city):
for building in city.buildings:
self.assertIsNotNone(building.name, 'building name is none')
self.assertIsNotNone(building.lod, 'building lod is none')
self.assertIsNotNone(building.type, 'building type is none')
self.assertIsNotNone(building.volume, 'building volume is none')
self.assertIsNotNone(building.detailed_polyhedron, 'building detailed polyhedron is none')

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8"?><!-- Generated by: --><!-- IFC -> cityGML Converter --><!-- (C) - Institute for Applied Computer Science --><!-- Forschungszentrum Karlsruhe --><!-- Not for commercial use --><!-- Generated by: IfcExplorer--><!-- cityGML Schema: 1.0.0 --><!-- Level of Detail 1--><!-- Creation Date: Tuesday, 23 November 2010 - 10:37:59--><!-- Edited Manually in Oxygen 8.2 --><!-- Modified by GMLOffset.xslt at Mon Dec 6 2010 --><!-- Version 2 Building located in the area of KIT Campus North)--><!-- Modified by GMLOffset.xslt at Wed Dec 8 2010 --><!-- Modified by GMLOffset.xslt at Wed Mar 29 2017 --><core:CityModel xsi:schemaLocation="http://www.opengis.net/citygml/2.0 http://schemas.opengis.net/citygml/2.0/cityGMLBase.xsd http://www.opengis.net/citygml/appearance/2.0 http://schemas.opengis.net/citygml/appearance/2.0/appearance.xsd http://www.opengis.net/citygml/building/2.0 http://schemas.opengis.net/citygml/building/2.0/building.xsd http://www.opengis.net/citygml/generics/2.0 http://schemas.opengis.net/citygml/generics/2.0/generics.xsd" xmlns:core="http://www.opengis.net/citygml/2.0" xmlns="http://www.opengis.net/citygml/profiles/base/2.0" xmlns:bldg="http://www.opengis.net/citygml/building/2.0" xmlns:gen="http://www.opengis.net/citygml/generics/2.0" xmlns:grp="http://www.opengis.net/citygml/cityobjectgroup/2.0" xmlns:app="http://www.opengis.net/citygml/appearance/2.0" xmlns:gml="http://www.opengis.net/gml" xmlns:xAL="urn:oasis:names:tc:ciq:xsdschema:xAL:2.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- Manually edited by KHH 23.01.2017, Address added, roof edge added -->
<gml:name>AC14-FZK-Haus</gml:name>
<gml:boundedBy>
<gml:Envelope srsDimension="3" srsName="urn:adv:crs:ETRS89_UTM32*DE_DHHN92_NH">
<gml:lowerCorner srsDimension="3">457842 5439083 111.8 </gml:lowerCorner>
<gml:upperCorner srsDimension="3">457854 5439093 118.317669 </gml:upperCorner>
</gml:Envelope>
</gml:boundedBy>
<core:cityObjectMember>
<bldg:Building gml:id="UUID_d281adfc-4901-0f52-540b-4cc1a9325f82">
<gml:description>FZK-Haus (Forschungszentrum Karlsruhe, now KIT), created by Karl-Heinz
Haefele </gml:description>
<gml:name>AC14-FZK-Haus</gml:name>
<core:creationDate>2017-01-23</core:creationDate>
<core:relativeToTerrain>entirelyAboveTerrain</core:relativeToTerrain>
<gen:measureAttribute name="GrossPlannedArea">
<gen:value uom="m2">120.00</gen:value>
</gen:measureAttribute>
<gen:stringAttribute name="ConstructionMethod">
<gen:value>New Building</gen:value>
</gen:stringAttribute>
<gen:stringAttribute name="IsLandmarked">
<gen:value>NO</gen:value>
</gen:stringAttribute>
<bldg:class codeSpace="http://www.sig3d.org/codelists/citygml/2.0/building/2.0/_AbstractBuilding_class.xml">1000</bldg:class>
<bldg:function codeSpace="http://www.sig3d.org/codelists/citygml/2.0/building/2.0/_AbstractBuilding_function.xml">1000</bldg:function>
<bldg:usage codeSpace="http://www.sig3d.org/codelists/citygml/2.0/building/2.0/_AbstractBuilding_usage.xml">1000</bldg:usage>
<bldg:yearOfConstruction>2020</bldg:yearOfConstruction>
<bldg:roofType codeSpace="http://www.sig3d.org/codelists/citygml/2.0/building/2.0/_AbstractBuilding_roofType.xml">1030</bldg:roofType>
<bldg:measuredHeight uom="m">6.52</bldg:measuredHeight>
<bldg:storeysAboveGround>2</bldg:storeysAboveGround>
<bldg:storeysBelowGround>0</bldg:storeysBelowGround>
<bldg:lod0FootPrint>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon>
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">457842 5439083 111.8 457842 5439093 111.8 457854 5439093 111.8 457854 5439083 111.8 457842 5439083 111.8 </gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</bldg:lod0FootPrint>
<bldg:lod0RoofEdge>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon>
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">457841.5 5439082.5 111.8 457841.5 5439093.5 111.8 457854.5 5439093.5 111.8 457854.5 5439082.5 111.8 457841.5 5439082.5 111.8 </gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</bldg:lod0RoofEdge>
<bldg:address>
<core:Address>
<core:xalAddress>
<xAL:AddressDetails>
<xAL:Locality Type="Town">
<xAL:LocalityName>Eggenstein-Leopoldshafen</xAL:LocalityName>
<xAL:Thoroughfare Type="Street">
<xAL:ThoroughfareNumber>4711</xAL:ThoroughfareNumber>
<xAL:ThoroughfareName>Spöcker Straße</xAL:ThoroughfareName>
</xAL:Thoroughfare>
<xAL:PostalCode>
<xAL:PostalCodeNumber>76344</xAL:PostalCodeNumber>
</xAL:PostalCode>
</xAL:Locality>
</xAL:AddressDetails>
</core:xalAddress>
</core:Address>
</bldg:address>
</bldg:Building>
</core:cityObjectMember>
</core:CityModel>

View File

@ -0,0 +1,116 @@
<?xml version="1.0" encoding="utf-8"?><!-- Generated by: --><!-- IFC -> cityGML Converter --><!-- (C) - Institute for Applied Computer Science --><!-- Forschungszentrum Karlsruhe --><!-- Not for commercial use --><!-- Generated by: IfcExplorer--><!-- cityGML Schema: 1.0.0 --><!-- Level of Detail 1--><!-- Creation Date: Tuesday, 23 November 2010 - 10:37:59--><!-- Edited Manually in Oxygen 8.2 --><!-- Modified by GMLOffset.xslt at Mon Dec 6 2010 --><!-- Version 2 Building located in the area of KIT Campus North)--><!-- Modified by GMLOffset.xslt at Wed Dec 8 2010 --><!-- Modified by GMLOffset.xslt at Wed Mar 29 2017 --><core:CityModel xsi:schemaLocation="http://www.opengis.net/citygml/2.0 http://schemas.opengis.net/citygml/2.0/cityGMLBase.xsd http://www.opengis.net/citygml/appearance/2.0 http://schemas.opengis.net/citygml/appearance/2.0/appearance.xsd http://www.opengis.net/citygml/building/2.0 http://schemas.opengis.net/citygml/building/2.0/building.xsd http://www.opengis.net/citygml/generics/2.0 http://schemas.opengis.net/citygml/generics/2.0/generics.xsd" xmlns:core="http://www.opengis.net/citygml/2.0" xmlns="http://www.opengis.net/citygml/profiles/base/2.0" xmlns:bldg="http://www.opengis.net/citygml/building/2.0" xmlns:gen="http://www.opengis.net/citygml/generics/2.0" xmlns:grp="http://www.opengis.net/citygml/cityobjectgroup/2.0" xmlns:app="http://www.opengis.net/citygml/appearance/2.0" xmlns:gml="http://www.opengis.net/gml" xmlns:xAL="urn:oasis:names:tc:ciq:xsdschema:xAL:2.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- Manually edited by KHH 23.01.2017, CityGML 2.0, Address added, roof edge added -->
<gml:name>AC14-FZK-Haus</gml:name>
<gml:boundedBy>
<gml:Envelope srsDimension="3" srsName="urn:adv:crs:ETRS89_UTM32*DE_DHHN92_NH">
<gml:lowerCorner srsDimension="3">457842 5439083 111.8 </gml:lowerCorner>
<gml:upperCorner srsDimension="3">457854 5439093 118.317669 </gml:upperCorner>
</gml:Envelope>
</gml:boundedBy>
<core:cityObjectMember>
<bldg:Building gml:id="UUID_d281adfc-4901-0f52-540b-4cc1a9325f82">
<gml:description>FZK-Haus (Forschungszentrum Karlsruhe, now KIT), created by Karl-Heinz
Haefele </gml:description>
<gml:name>AC14-FZK-Haus</gml:name>
<core:creationDate>2017-01-23</core:creationDate>
<core:relativeToTerrain>entirelyAboveTerrain</core:relativeToTerrain>
<gen:measureAttribute name="GrossPlannedArea">
<gen:value uom="m2">120.00</gen:value>
</gen:measureAttribute>
<gen:stringAttribute name="ConstructionMethod">
<gen:value>New Building</gen:value>
</gen:stringAttribute>
<gen:stringAttribute name="IsLandmarked">
<gen:value>NO</gen:value>
</gen:stringAttribute>
<bldg:class codeSpace="http://www.sig3d.org/codelists/citygml/2.0/building/2.0/_AbstractBuilding_class.xml">1000</bldg:class>
<bldg:function codeSpace="http://www.sig3d.org/codelists/citygml/2.0/building/2.0/_AbstractBuilding_function.xml">1000</bldg:function>
<bldg:usage codeSpace="http://www.sig3d.org/codelists/citygml/2.0/building/2.0/_AbstractBuilding_usage.xml">1000</bldg:usage>
<bldg:yearOfConstruction>2020</bldg:yearOfConstruction>
<bldg:roofType codeSpace="http://www.sig3d.org/codelists/citygml/2.0/building/2.0/_AbstractBuilding_roofType.xml">1030</bldg:roofType>
<bldg:measuredHeight uom="m">6.52</bldg:measuredHeight>
<bldg:storeysAboveGround>2</bldg:storeysAboveGround>
<bldg:storeysBelowGround>0</bldg:storeysBelowGround>
<bldg:lod1Solid>
<gml:Solid>
<gml:exterior>
<gml:CompositeSurface>
<gml:surfaceMember>
<gml:Polygon>
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">457842 5439083 111.8 457842 5439093 111.8 457854 5439093 111.8 457854 5439083 111.8 457842 5439083 111.8 </gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon>
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">457842 5439083 118.31769 457854 5439083 118.31769 457854 5439093 118.31769 457842 5439093 118.31769 457842 5439083 118.31769 </gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon>
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">457842 5439083 111.8 457842 5439083 118.31769 457842 5439093 118.31769 457842 5439093 111.8 457842 5439083 111.8 </gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon>
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">457842 5439093 111.8 457842 5439093 118.31769 457854 5439093 118.31769 457854 5439093 111.8 457842 5439093 111.8 </gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon>
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">457854 5439093 111.8 457854 5439093 118.31769 457854 5439083 118.31769 457854 5439083 111.8 457854 5439093 111.8 </gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
<gml:surfaceMember>
<gml:Polygon>
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">457854 5439083 111.8 457854 5439083 118.31769 457842 5439083 118.31769 457842 5439083 111.8 457854 5439083 111.8 </gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:CompositeSurface>
</gml:exterior>
</gml:Solid>
</bldg:lod1Solid>
<bldg:address>
<core:Address>
<core:xalAddress>
<xAL:AddressDetails>
<xAL:Locality Type="Town">
<xAL:LocalityName>Eggenstein-Leopoldshafen</xAL:LocalityName>
<xAL:Thoroughfare Type="Street">
<xAL:ThoroughfareNumber>4711</xAL:ThoroughfareNumber>
<xAL:ThoroughfareName>Spöcker Straße</xAL:ThoroughfareName>
</xAL:Thoroughfare>
<xAL:PostalCode>
<xAL:PostalCodeNumber>76344</xAL:PostalCodeNumber>
</xAL:PostalCode>
</xAL:Locality>
</xAL:AddressDetails>
</core:xalAddress>
</core:Address>
</bldg:address>
</bldg:Building>
</core:cityObjectMember>
</core:CityModel>

View File

@ -0,0 +1,240 @@
<?xml version="1.0" encoding="utf-8"?><!-- IFC to CityGML by IFCExplorer KIT --><!-- CityGML to Sketchup by Sketchup CityGML Plugin FH GelsenKirchen --><!--CityGML Dataset produced with CityGML Export Plugin for Sketchup by GeoRES --><!--http://www.geores.de --><!-- Edited Manually in Oxygen 8.2 --><!-- Modified by GMLOffset.xslt at Mon Dec 6 2010 --><!-- Version 2 Building located in the area of KIT Campus North)--><!-- Modified by GMLOffset.xslt at Wed Dec 8 2010 --><!-- Modified by GMLOffset.xslt at Wed Mar 29 2017 --><core:CityModel xsi:schemaLocation="http://www.opengis.net/citygml/2.0 http://schemas.opengis.net/citygml/2.0/cityGMLBase.xsd http://www.opengis.net/citygml/appearance/2.0 http://schemas.opengis.net/citygml/appearance/2.0/appearance.xsd http://www.opengis.net/citygml/building/2.0 http://schemas.opengis.net/citygml/building/2.0/building.xsd http://www.opengis.net/citygml/generics/2.0 http://schemas.opengis.net/citygml/generics/2.0/generics.xsd" xmlns:core="http://www.opengis.net/citygml/2.0" xmlns="http://www.opengis.net/citygml/profiles/base/2.0" xmlns:bldg="http://www.opengis.net/citygml/building/2.0" xmlns:gen="http://www.opengis.net/citygml/generics/2.0" xmlns:grp="http://www.opengis.net/citygml/cityobjectgroup/2.0" xmlns:app="http://www.opengis.net/citygml/appearance/2.0" xmlns:gml="http://www.opengis.net/gml" xmlns:xAL="urn:oasis:names:tc:ciq:xsdschema:xAL:2.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- Manually edited by KHH 23.01.2017, CityGML 2.0, Address added, Codespaces added -->
<gml:name>AC14-FZK-Haus</gml:name>
<gml:boundedBy>
<gml:Envelope srsDimension="3" srsName="urn:adv:crs:ETRS89_UTM32*DE_DHHN92_NH">
<gml:lowerCorner srsDimension="3">457842 5439083 111.8 </gml:lowerCorner>
<gml:upperCorner srsDimension="3">457854 5439093 118.317669 </gml:upperCorner>
</gml:Envelope>
</gml:boundedBy>
<core:cityObjectMember>
<bldg:Building gml:id="UUID_d281adfc-4901-0f52-540b-4cc1a9325f82">
<gml:description>FZK-Haus (Forschungszentrum Karlsruhe, now KIT), created by Karl-Heinz
Haefele </gml:description>
<gml:name>AC14-FZK-Haus</gml:name>
<core:creationDate>2017-01-23</core:creationDate>
<core:relativeToTerrain>entirelyAboveTerrain</core:relativeToTerrain>
<gen:measureAttribute name="GrossPlannedArea">
<gen:value uom="m2">120.00</gen:value>
</gen:measureAttribute>
<gen:stringAttribute name="ConstructionMethod">
<gen:value>New Building</gen:value>
</gen:stringAttribute>
<gen:stringAttribute name="IsLandmarked">
<gen:value>NO</gen:value>
</gen:stringAttribute>
<bldg:class codeSpace="http://www.sig3d.org/codelists/citygml/2.0/building/2.0/_AbstractBuilding_class.xml">1000</bldg:class>
<bldg:function codeSpace="http://www.sig3d.org/codelists/citygml/2.0/building/2.0/_AbstractBuilding_function.xml">1000</bldg:function>
<bldg:usage codeSpace="http://www.sig3d.org/codelists/citygml/2.0/building/2.0/_AbstractBuilding_usage.xml">1000</bldg:usage>
<bldg:yearOfConstruction>2020</bldg:yearOfConstruction>
<bldg:roofType codeSpace="http://www.sig3d.org/codelists/citygml/2.0/building/2.0/_AbstractBuilding_roofType.xml">1030</bldg:roofType>
<bldg:measuredHeight uom="m">6.52</bldg:measuredHeight>
<bldg:storeysAboveGround>2</bldg:storeysAboveGround>
<bldg:storeysBelowGround>0</bldg:storeysBelowGround>
<bldg:lod2Solid>
<gml:Solid>
<gml:exterior>
<gml:CompositeSurface>
<!--Outer Wall 1 (West) -->
<gml:surfaceMember xlink:href="#PolyID7350_878_759628_120742"> </gml:surfaceMember>
<!--Outer Wall 1 (West) -->
<!--Outer Wall 2 (South) -->
<gml:surfaceMember xlink:href="#PolyID7351_1722_416019_316876" />
<!--Outer Wall 2 (South) -->
<!--Outer Wall 3 (East) -->
<gml:surfaceMember xlink:href="#PolyID7352_230_209861_355851" />
<!--Outer Wall 3 (East) -->
<!--Roof 1 (North) -->
<gml:surfaceMember xlink:href="#PolyID7353_166_774155_320806" />
<!--Roof 1 (North) -->
<!--Outer Wall 4 (North) -->
<gml:surfaceMember xlink:href="#PolyID7354_1362_450904_410226" />
<!--Outer Wall 2 (North) -->
<!--Roof 2 (South) -->
<gml:surfaceMember xlink:href="#PolyID7355_537_416207_260034" />
<!--Roof 2 (South) -->
<!--Base Surface -->
<gml:surfaceMember xlink:href="#PolyID7356_612_880782_415367" />
<!--Base Surface -->
</gml:CompositeSurface>
</gml:exterior>
</gml:Solid>
</bldg:lod2Solid>
<bldg:boundedBy>
<bldg:WallSurface gml:id="GML_5856d7ad-5e34-498a-817b-9544bfbb1475">
<gml:name>Outer Wall 1 (West)</gml:name>
<bldg:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon gml:id="PolyID7350_878_759628_120742">
<gml:exterior>
<gml:LinearRing gml:id="PolyID7350_878_759628_120742_0">
<gml:pos>457842 5439088 118.317691453624 </gml:pos>
<gml:pos>457842 5439093 115.430940107676 </gml:pos>
<gml:pos>457842 5439093 111.8 </gml:pos>
<gml:pos>457842 5439083 111.8 </gml:pos>
<gml:pos>457842 5439083 115.430940107676 </gml:pos>
<gml:pos>457842 5439088 118.317691453624 </gml:pos>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</bldg:lod2MultiSurface>
</bldg:WallSurface>
</bldg:boundedBy>
<bldg:boundedBy>
<bldg:WallSurface gml:id="GML_d38cf762-c29d-4491-88c9-bdc89e141978">
<gml:name>Outer Wall 2 (South)</gml:name>
<bldg:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon gml:id="PolyID7351_1722_416019_316876">
<gml:exterior>
<gml:LinearRing gml:id="PolyID7351_1722_416019_316876_0">
<gml:pos>457854 5439083 115.430940107676 </gml:pos>
<gml:pos>457842 5439083 115.430940107676 </gml:pos>
<gml:pos>457842 5439083 111.8 </gml:pos>
<gml:pos>457854 5439083 111.8 </gml:pos>
<gml:pos>457854 5439083 115.430940107676 </gml:pos>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</bldg:lod2MultiSurface>
</bldg:WallSurface>
</bldg:boundedBy>
<bldg:boundedBy>
<bldg:WallSurface gml:id="GML_8e5db638-e46a-4739-a98a-2fc2d39c9069">
<gml:name>Outer Wall 3 (East)</gml:name>
<bldg:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon gml:id="PolyID7352_230_209861_355851">
<gml:exterior>
<gml:LinearRing gml:id="PolyID7352_230_209861_355851_0">
<gml:pos>457854 5439088 118.317691453624 </gml:pos>
<gml:pos>457854 5439083 115.430940107676 </gml:pos>
<gml:pos>457854 5439083 111.8 </gml:pos>
<gml:pos>457854 5439093 111.8 </gml:pos>
<gml:pos>457854 5439093 115.430940107676 </gml:pos>
<gml:pos>457854 5439088 118.317691453624 </gml:pos>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</bldg:lod2MultiSurface>
</bldg:WallSurface>
</bldg:boundedBy>
<bldg:boundedBy>
<bldg:RoofSurface gml:id="GML_875d470b-32b4-4985-a4c8-0f02caa342a2">
<gml:name>Roof 1 (North)</gml:name>
<bldg:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon gml:id="PolyID7353_166_774155_320806">
<gml:exterior>
<gml:LinearRing gml:id="PolyID7353_166_774155_320806_0">
<gml:pos>457842 5439088 118.317691453624 </gml:pos>
<gml:pos>457854 5439088 118.317691453624 </gml:pos>
<gml:pos>457854 5439093 115.430940107676 </gml:pos>
<gml:pos>457842 5439093 115.430940107676 </gml:pos>
<gml:pos>457842 5439088 118.317691453624 </gml:pos>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</bldg:lod2MultiSurface>
</bldg:RoofSurface>
</bldg:boundedBy>
<bldg:boundedBy>
<bldg:WallSurface gml:id="GML_0f30f604-e70d-4dfe-ba35-853bc69609cc">
<gml:name>Outer Wall 4 (North)</gml:name>
<bldg:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon gml:id="PolyID7354_1362_450904_410226">
<gml:exterior>
<gml:LinearRing gml:id="PolyID7354_1362_450904_410226_0">
<gml:pos>457842 5439093 115.430940107676 </gml:pos>
<gml:pos>457854 5439093 115.430940107676 </gml:pos>
<gml:pos>457854 5439093 111.8 </gml:pos>
<gml:pos>457842 5439093 111.8 </gml:pos>
<gml:pos>457842 5439093 115.430940107676 </gml:pos>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</bldg:lod2MultiSurface>
</bldg:WallSurface>
</bldg:boundedBy>
<bldg:boundedBy>
<bldg:RoofSurface gml:id="GML_eeb6796a-e261-4d3b-a6f2-475940cca80a">
<gml:name>Roof 2 (South)</gml:name>
<bldg:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon gml:id="PolyID7355_537_416207_260034">
<gml:exterior>
<gml:LinearRing gml:id="PolyID7355_537_416207_260034_0">
<gml:pos>457854 5439083 115.430940107676 </gml:pos>
<gml:pos>457854 5439088 118.317691453624 </gml:pos>
<gml:pos>457842 5439088 118.317691453624 </gml:pos>
<gml:pos>457842 5439083 115.430940107676 </gml:pos>
<gml:pos>457854 5439083 115.430940107676 </gml:pos>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</bldg:lod2MultiSurface>
</bldg:RoofSurface>
</bldg:boundedBy>
<bldg:boundedBy>
<bldg:GroundSurface gml:id="GML_257a8dde-8194-4ca3-b581-abd591dcd6a3">
<gml:description>Bodenplatte</gml:description>
<gml:name>Base Surface</gml:name>
<bldg:lod2MultiSurface>
<gml:MultiSurface>
<gml:surfaceMember>
<gml:Polygon gml:id="PolyID7356_612_880782_415367">
<gml:exterior>
<gml:LinearRing gml:id="PolyID7356_612_880782_415367_0">
<gml:pos>457854 5439083 111.8 </gml:pos>
<gml:pos>457842 5439083 111.8 </gml:pos>
<gml:pos>457842 5439093 111.8 </gml:pos>
<gml:pos>457854 5439093 111.8 </gml:pos>
<gml:pos>457854 5439083 111.8 </gml:pos>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</gml:surfaceMember>
</gml:MultiSurface>
</bldg:lod2MultiSurface>
</bldg:GroundSurface>
</bldg:boundedBy>
<bldg:address>
<core:Address>
<core:xalAddress>
<xAL:AddressDetails>
<xAL:Locality Type="Town">
<xAL:LocalityName>Eggenstein-Leopoldshafen</xAL:LocalityName>
<xAL:Thoroughfare Type="Street">
<xAL:ThoroughfareNumber>4711</xAL:ThoroughfareNumber>
<xAL:ThoroughfareName>Spöcker Straße</xAL:ThoroughfareName>
</xAL:Thoroughfare>
<xAL:PostalCode>
<xAL:PostalCodeNumber>76344</xAL:PostalCodeNumber>
</xAL:PostalCode>
</xAL:Locality>
</xAL:AddressDetails>
</core:xalAddress>
</core:Address>
</bldg:address>
</bldg:Building>
</core:cityObjectMember>
</core:CityModel>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,18 @@
{ "type": "FeatureCollection",
"features": [
{ "type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[ [[-73.5027962600162, 45.6572759731914], [-73.5027463586105, 45.6572669735158], [-73.5027513584185, 45.6572530729948], [-73.5026715592026, 45.6572412737672], [-73.5026410593539, 45.6573430727752], [-73.5027703584728, 45.6573621728624], [-73.5027962600162, 45.6572759731914]] ]
]
},
"properties": {
"geom": {"type": "Polygon", "crs": {"type": "name", "properties": {"name": "urn:ogc:def:crs:EPSG::4326"}}, "coordinates": [[[3849322.0855625975, 6060583.24800576], [3849326.3956304314, 6060584.796717078], [3849327.0180495544, 6060583.089519385], [3849333.725799462, 6060585.837955164], [3849328.71788522, 6060598.03498192], [3849317.850609142, 6060593.57976506], [3849322.0855625975, 6060583.24800576]]]},
"height": 13.0790429485,
"year_built": 2000
}
}
]
}