Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
2702c77a33
|
@ -36,6 +36,9 @@ class Surface:
|
|||
self._min_x = None
|
||||
self._min_y = None
|
||||
self._min_z = None
|
||||
self._max_x = None
|
||||
self._max_y = None
|
||||
self._max_z = None
|
||||
self._shared_surfaces = []
|
||||
self._global_irradiance = dict()
|
||||
self._perimeter_polygon = None
|
||||
|
@ -171,6 +174,21 @@ class Surface:
|
|||
self._perimeter_points_list = np.reshape(s, len(s) * 3)
|
||||
return self._perimeter_points_list
|
||||
|
||||
def _max_coord(self, axis):
|
||||
if axis == 'x':
|
||||
axis = 0
|
||||
elif axis == 'y':
|
||||
axis = 1
|
||||
else:
|
||||
axis = 2
|
||||
max_coordinate = ''
|
||||
for point in self.points:
|
||||
if max_coordinate == '':
|
||||
max_coordinate = point[axis]
|
||||
elif max_coordinate < point[axis]:
|
||||
max_coordinate = point[axis]
|
||||
return max_coordinate
|
||||
|
||||
def _min_coord(self, axis):
|
||||
if axis == 'x':
|
||||
axis = 0
|
||||
|
@ -186,6 +204,36 @@ class Surface:
|
|||
min_coordinate = point[axis]
|
||||
return min_coordinate
|
||||
|
||||
@property
|
||||
def max_x(self):
|
||||
"""
|
||||
Surface maximal x value
|
||||
:return: float
|
||||
"""
|
||||
if self._max_x is None:
|
||||
self._max_x = self._max_coord('x')
|
||||
return self._max_x
|
||||
|
||||
@property
|
||||
def max_y(self):
|
||||
"""
|
||||
Surface maximal y value
|
||||
:return: float
|
||||
"""
|
||||
if self._max_y is None:
|
||||
self._max_y = self._max_coord('y')
|
||||
return self._max_y
|
||||
|
||||
@property
|
||||
def max_z(self):
|
||||
"""
|
||||
Surface maximal z value
|
||||
:return: float
|
||||
"""
|
||||
if self._max_z is None:
|
||||
self._max_z = self._max_coord('z')
|
||||
return self._max_z
|
||||
|
||||
@property
|
||||
def min_x(self):
|
||||
"""
|
||||
|
|
|
@ -4,8 +4,8 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|||
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||
Contributors Pilar Monsalvete Álvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
import uuid
|
||||
from typing import List, TypeVar
|
||||
|
||||
from city_model_structure.attributes.surface import Surface
|
||||
from city_model_structure.attributes.usage_zone import UsageZone
|
||||
|
||||
|
@ -17,12 +17,10 @@ class ThermalZone:
|
|||
"""
|
||||
ThermalZone class
|
||||
"""
|
||||
def __init__(self, surfaces, is_heated, is_cooled):
|
||||
def __init__(self, surfaces):
|
||||
self._surfaces = surfaces
|
||||
self._floor_area = None
|
||||
self._bounded = None
|
||||
self._is_heated = is_heated
|
||||
self._is_cooled = is_cooled
|
||||
self._is_mechanically_ventilated = None
|
||||
self._additional_thermal_bridge_u_value = None
|
||||
self._effective_thermal_capacity = None
|
||||
|
@ -32,6 +30,15 @@ class ThermalZone:
|
|||
self._usage_zones = None
|
||||
self._volume = None
|
||||
self._volume_geometry = None
|
||||
self._id = None
|
||||
self._is_heated = False
|
||||
self._is_cooled = False
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
if self._id is None:
|
||||
self._id = uuid.uuid4()
|
||||
return self._id
|
||||
|
||||
@property
|
||||
def is_heated(self):
|
||||
|
@ -41,6 +48,14 @@ class ThermalZone:
|
|||
"""
|
||||
return self._is_heated
|
||||
|
||||
@is_heated.setter
|
||||
def is_heated(self, value):
|
||||
"""
|
||||
Set thermal zone heated flag
|
||||
:return: Boolean
|
||||
"""
|
||||
self._is_heated = value
|
||||
|
||||
@property
|
||||
def is_cooled(self):
|
||||
"""
|
||||
|
@ -49,6 +64,14 @@ class ThermalZone:
|
|||
"""
|
||||
return self._is_cooled
|
||||
|
||||
@is_cooled.setter
|
||||
def is_cooled(self, value):
|
||||
"""
|
||||
Set thermal zone cooled flag
|
||||
:return: Boolean
|
||||
"""
|
||||
self._is_cooled = value
|
||||
|
||||
@property
|
||||
def is_mechanically_ventilated(self):
|
||||
"""
|
||||
|
|
|
@ -4,6 +4,7 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|||
Copyright © 2020 Project Author Pilar Monsalvete pilar_monsalvete@yahoo.es
|
||||
Contributors Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||
"""
|
||||
import uuid
|
||||
from typing import List, TypeVar
|
||||
|
||||
InternalGains = TypeVar('InternalGains')
|
||||
|
@ -17,6 +18,7 @@ class UsageZone:
|
|||
UsageZone class
|
||||
"""
|
||||
def __init__(self):
|
||||
self._id = None
|
||||
self._usage = None
|
||||
self._internal_gains = None
|
||||
self._heating_setpoint = None
|
||||
|
@ -36,6 +38,12 @@ class UsageZone:
|
|||
self._ventilation_schedule = None
|
||||
self._volume_geometry = None
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
if self._id is None:
|
||||
self._id = uuid.uuid4()
|
||||
return self._id
|
||||
|
||||
@property
|
||||
def lights(self) -> List[Lighting]:
|
||||
return self._lights
|
||||
|
|
|
@ -33,8 +33,6 @@ class Building(CityObject):
|
|||
self._function = function
|
||||
self._city_lower_corner = city_lower_corner
|
||||
self._building_lower_corner = None
|
||||
self._heated = None
|
||||
self._cooled = None
|
||||
self._average_storey_height = None
|
||||
self._storeys_above_ground = None
|
||||
self._floor_area = None
|
||||
|
@ -59,7 +57,7 @@ class Building(CityObject):
|
|||
self._thermal_zones = []
|
||||
if self.lod < 4:
|
||||
# for lod under 4 is just one thermal zone
|
||||
self._thermal_zones.append(ThermalZone(self.surfaces, self._heated, self._cooled))
|
||||
self._thermal_zones.append(ThermalZone(self.surfaces))
|
||||
|
||||
for t_zones in self._thermal_zones:
|
||||
t_zones.bounded = [ThermalBoundary(s, [t_zones]) for s in t_zones.surfaces]
|
||||
|
@ -81,6 +79,28 @@ class Building(CityObject):
|
|||
"""
|
||||
return self._grounds
|
||||
|
||||
@property
|
||||
def is_heated(self):
|
||||
"""
|
||||
Get building heated flag
|
||||
:return: Boolean
|
||||
"""
|
||||
for thermal_zone in self.thermal_zones:
|
||||
if thermal_zone.is_heated:
|
||||
return thermal_zone.is_heated
|
||||
return False
|
||||
|
||||
@property
|
||||
def is_cooled(self):
|
||||
"""
|
||||
Get building cooled flag
|
||||
:return: Boolean
|
||||
"""
|
||||
for thermal_zone in self.thermal_zones:
|
||||
if thermal_zone.is_cooled:
|
||||
return thermal_zone.is_cooled
|
||||
return False
|
||||
|
||||
@property
|
||||
def roofs(self) -> [Surface]:
|
||||
"""
|
||||
|
@ -110,10 +130,9 @@ class Building(CityObject):
|
|||
:param values: [UsageZones]
|
||||
:return: None
|
||||
"""
|
||||
# ToDo: this is only valid for one usage zone need to be revised for multiple usage zones.
|
||||
self._usage_zones = values
|
||||
for thermal_zone in self.thermal_zones:
|
||||
thermal_zone.usage_zones = [(100, usage_zone) for usage_zone in values]
|
||||
thermal_zone.usage_zones = values
|
||||
|
||||
@property
|
||||
def terrains(self) -> List[Surface]:
|
||||
|
|
|
@ -5,6 +5,7 @@ Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@conc
|
|||
"""
|
||||
import xmltodict
|
||||
import uuid
|
||||
import datetime
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
|
@ -27,7 +28,7 @@ class EnergyAde:
|
|||
'@xmlns:tun':'http://www.opengis.net/citygml/tunnel/2.0',
|
||||
'@xmlns:tex':'http://www.opengis.net/citygml/texturedsurface/2.0',
|
||||
'@xmlns:gml':'http://www.opengis.net/gml',
|
||||
'@xmlns:gen':'http://www.opengis.net/citygml/generics/2.0',
|
||||
'@xmlns:genobj':'http://www.opengis.net/citygml/generics/2.0',
|
||||
'@xmlns:dem':'http://www.opengis.net/citygml/relief/2.0',
|
||||
'@xmlns:app':'http://www.opengis.net/citygml/appearance/2.0',
|
||||
'@xmlns:luse':'http://www.opengis.net/citygml/landuse/2.0',
|
||||
|
@ -37,6 +38,7 @@ class EnergyAde:
|
|||
'@xmlns:pbase':'http://www.opengis.net/citygml/profiles/base/2.0',
|
||||
'@xmlns:smil20': 'http://www.w3.org/2001/SMIL20/',
|
||||
'@xmlns:bldg':'http://www.opengis.net/citygml/building/2.0',
|
||||
'@xmlns:energy': "http://www.sig3d.org/citygml/2.0/energy/1.0",
|
||||
'@xmlns:core':'http://www.opengis.net/citygml/2.0',
|
||||
'@xmlns:grp':'http://www.opengis.net/citygml/cityobjectgroup/2.0',
|
||||
'gml:boundedBy': {
|
||||
|
@ -53,11 +55,31 @@ class EnergyAde:
|
|||
for building in self._city.buildings:
|
||||
building_dic = {
|
||||
'bldg:Building': {
|
||||
'@gml:id': building.name
|
||||
'@gml:id': building.name,
|
||||
'gml:description': f'Building {building.name} at {self._city.name}',
|
||||
'gml:name': f'{building.name}',
|
||||
'core:creationDate': datetime.datetime.now().strftime('%Y-%m-%d')
|
||||
}
|
||||
}
|
||||
building_dic = EnergyAde._measures(building, building_dic)
|
||||
building_dic = EnergyAde._building_geometry(building, building_dic, self._city)
|
||||
building_dic['bldg:Building']['energy:volume'] = {
|
||||
'energy:VolumeType': {
|
||||
'energy:type':'grossVolume',
|
||||
'energy:value': {
|
||||
'@uom': 'm3',
|
||||
'energy:value': building.volume
|
||||
}
|
||||
}
|
||||
}
|
||||
building_dic['bldg:Building']['energy:referencePoint'] = {
|
||||
'gml:Point': {
|
||||
'@srsName': self._city.srs_name,
|
||||
'@gml:id': f'GML_{uuid.uuid4()}',
|
||||
'gml:Pos': f'{" ".join(map(str,building.centroid))}'
|
||||
}
|
||||
}
|
||||
building_dic['bldg:Building']['energy:thermalZone'] = EnergyAde._thermal_zones(building,self._city)
|
||||
buildings.append(building_dic)
|
||||
|
||||
energy_ade['core:CityModel']['core:cityObjectMember'] = buildings
|
||||
|
@ -76,21 +98,20 @@ class EnergyAde:
|
|||
if measure is not None:
|
||||
measures.append(measure)
|
||||
if len(measures) != 0:
|
||||
building_dic['genobj:measureAttribute'] = measures
|
||||
building_dic['bldg:Building']['genobj:measureAttribute'] = measures
|
||||
|
||||
periods = []
|
||||
demands = []
|
||||
for key in building.heating:
|
||||
if key != 'year':
|
||||
period = EnergyAde._period(building.heating, key, 'Heating energy', 'INSEL')
|
||||
periods.append(period)
|
||||
demand = EnergyAde._demand(building.heating, key, 'Heating energy', 'INSEL')
|
||||
demands.append(demand)
|
||||
|
||||
for key in building.cooling:
|
||||
if key != 'year':
|
||||
period = EnergyAde._period(building.cooling, key, 'Cooling energy', 'INSEL')
|
||||
periods.append(period)
|
||||
|
||||
if len(periods) != 0:
|
||||
building_dic['energy:demands'] = {'energy:EnergyDemand': periods}
|
||||
demand = EnergyAde._demand(building.cooling, key, 'Cooling energy', 'INSEL')
|
||||
demands.append(demand)
|
||||
if len(demands) != 0:
|
||||
building_dic['bldg:Building']['energy:demands'] = demands
|
||||
|
||||
return building_dic
|
||||
|
||||
|
@ -108,45 +129,46 @@ class EnergyAde:
|
|||
return measure
|
||||
|
||||
@staticmethod
|
||||
def _period(measure_dict, key_value, description, source):
|
||||
period = {
|
||||
'@gml:id': uuid.uuid4(),
|
||||
'energy:energyAmount': {
|
||||
'energy:RegularTimeSeries': {
|
||||
'energy:variableProperties': {
|
||||
'energy:TimeValuesProperties': {
|
||||
'energy:acquisitionMethod': 'simulation',
|
||||
'energy:source': source,
|
||||
'energy:thematicDescription': description,
|
||||
},
|
||||
'energy:timeInterval': {
|
||||
'@unit': key_value,
|
||||
'#text': '1',
|
||||
},
|
||||
'energy:values': {
|
||||
'@uom': 'kWh',
|
||||
'#text': ' '.join([str(float(e) / 1000) for e in measure_dict[key_value][source]])
|
||||
def _demand(measure_dict, key_value, description, source):
|
||||
demand = {
|
||||
'energy:EnergyDemand': {
|
||||
'@gml:id': f'GML_{uuid.uuid4()}',
|
||||
'energy:energyAmount': {
|
||||
'energy:RegularTimeSeries': {
|
||||
'energy:variableProperties': {
|
||||
'energy:TimeValuesProperties': {
|
||||
'energy:acquisitionMethod': 'simulation',
|
||||
'energy:source': source,
|
||||
'energy:thematicDescription': description,
|
||||
},
|
||||
'energy:timeInterval': {
|
||||
'@unit': key_value,
|
||||
'#text': '1',
|
||||
},
|
||||
'energy:values': {
|
||||
'@uom': 'kWh',
|
||||
'#text': ' '.join([str(float(e) / 1000) for e in measure_dict[key_value][source]])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'energy:endUse': 'spaceHeating'
|
||||
}
|
||||
}
|
||||
return period
|
||||
return demand
|
||||
|
||||
@staticmethod
|
||||
def _building_geometry(building, building_dic, city):
|
||||
|
||||
building_dic['bldg:function'] = building.function
|
||||
building_dic['bldg:usage'] = ', '.join([u.usage for u in building.usage_zones])
|
||||
building_dic['bldg:yearOfConstruction'] = building.year_of_construction
|
||||
building_dic['bldg:roofType'] = building.roof_type
|
||||
|
||||
building_dic['bldg:measuredHeight'] = {
|
||||
building_dic['bldg:Building']['bldg:function'] = building.function
|
||||
building_dic['bldg:Building']['bldg:usage'] = ', '.join([u.usage for u in building.usage_zones])
|
||||
building_dic['bldg:Building']['bldg:yearOfConstruction'] = building.year_of_construction
|
||||
building_dic['bldg:Building']['bldg:roofType'] = building.roof_type
|
||||
building_dic['bldg:Building']['bldg:measuredHeight'] = {
|
||||
'@uom': 'm',
|
||||
'#text': f'{building.max_height}'
|
||||
}
|
||||
|
||||
building_dic['bldg:storeysAboveGround'] = building.storeys_above_ground
|
||||
building_dic['bldg:Building']['bldg:storeysAboveGround'] = building.storeys_above_ground
|
||||
if building.lod == 1:
|
||||
building_dic = EnergyAde._lod1(building, building_dic, city)
|
||||
elif building.lod == 2:
|
||||
|
@ -178,8 +200,6 @@ class EnergyAde:
|
|||
else:
|
||||
surface_type = 'bldg:RoofSurface'
|
||||
|
||||
|
||||
|
||||
surface_dic = {
|
||||
surface_type: {
|
||||
'@gml:id': f'GML_{uuid.uuid4()}',
|
||||
|
@ -198,13 +218,13 @@ class EnergyAde:
|
|||
'surfaceMember': {
|
||||
'gml:Polygon': {
|
||||
'@srsName': city.srs_name,
|
||||
'@gml:id': f'#PolyId{surface.name}',
|
||||
'@gml:id': f'PolyId{surface.name}',
|
||||
'gml:exterior': {
|
||||
'gml:LinearRing': {
|
||||
'@gml:id': f'#PolyId{surface.name}_0',
|
||||
'@gml:id': f'PolyId{surface.name}_0',
|
||||
'gml:posList': {
|
||||
'@srsDimension': '3',
|
||||
'@count': len(surface.points_list) + 1,
|
||||
'@count': len(surface.points) + 1,
|
||||
'#text': f'{" ".join(map(str, surface.points_list))} {" ".join(map(str, surface.points[0]))}'
|
||||
}
|
||||
}
|
||||
|
@ -215,10 +235,8 @@ class EnergyAde:
|
|||
}
|
||||
}
|
||||
}
|
||||
print(surface_dic)
|
||||
boundaries.append(surface_dic)
|
||||
print(surface_dic)
|
||||
building_dic['bldg:lod2Solid'] = {
|
||||
building_dic['bldg:Building']['bldg:lod2Solid'] = {
|
||||
'gml:Solid': {
|
||||
'@gml:id': f'GML_{uuid.uuid4()}',
|
||||
'gml:exterior': {
|
||||
|
@ -231,6 +249,47 @@ class EnergyAde:
|
|||
}
|
||||
}
|
||||
|
||||
building_dic['gml:boundedBy'] = boundaries
|
||||
print(building_dic)
|
||||
return building_dic
|
||||
building_dic['bldg:Building']['gml:boundedBy'] = boundaries
|
||||
return building_dic
|
||||
|
||||
@staticmethod
|
||||
def _thermal_zones(building, city):
|
||||
thermal_zones = []
|
||||
for index, thermal_zone in enumerate(building.thermal_zones):
|
||||
usage_zones = []
|
||||
for usage_zone in thermal_zone.usage_zones:
|
||||
usage_zones.append({'@xlink:href': f'#GML_{usage_zone.id}'})
|
||||
|
||||
thermal_zone_dic = {
|
||||
'energy:ThermalZone': {
|
||||
'@gml:id': f'GML_{thermal_zone.id}',
|
||||
'gml:name': f'Thermal zone {index} in {building.name} building',
|
||||
'energy:contains': [],
|
||||
'energy:floorArea': {
|
||||
'energy:FloorArea' : {
|
||||
'energy:type': 'grossFloorArea',
|
||||
'energy:value': {
|
||||
'@uom': 'm2',
|
||||
'#text': f'{thermal_zone.floor_area}'
|
||||
}
|
||||
}
|
||||
},
|
||||
'energy:volume': {
|
||||
'energy:VolumeType': {
|
||||
'energy:type': 'grossVolume',
|
||||
'energy:value': {
|
||||
'@uom': 'm3',
|
||||
#todo: for now we have just one thermal zone, therefore is the building volume, this need to be changed
|
||||
'#text': f'{building.volume}'
|
||||
}
|
||||
}
|
||||
},
|
||||
'energy:isCooled': f'{thermal_zone.is_cooled}',
|
||||
'energy:isHeated': f'{thermal_zone.is_heated}',
|
||||
|
||||
}
|
||||
}
|
||||
thermal_zone_dic['energy:ThermalZone']['energy:contains'] = usage_zones
|
||||
thermal_zones.append(thermal_zone_dic)
|
||||
print(thermal_zones)
|
||||
return thermal_zones
|
Loading…
Reference in New Issue
Block a user