forked from s_ranjbar/city_retrofit
Import the shared code files into the new repository
This commit is contained in:
parent
4ecefaf2d0
commit
0fe85d5956
43
city_model_structure/city.py
Normal file
43
city_model_structure/city.py
Normal file
|
@ -0,0 +1,43 @@
|
|||
from city_model_structure.city_object import CityObject
|
||||
from typing import List, Union
|
||||
|
||||
|
||||
class City:
|
||||
def __init__(self, lower_corner, upper_corner, city_objects, srs_name):
|
||||
self._city_objects = None
|
||||
self._name = None
|
||||
self._lower_corner = lower_corner
|
||||
self._upper_corner = upper_corner
|
||||
self._city_objects = city_objects
|
||||
self._srs_name = srs_name
|
||||
|
||||
@property
|
||||
def city_objects(self) -> List[CityObject]:
|
||||
return self._city_objects
|
||||
|
||||
@property
|
||||
def lower_corner(self):
|
||||
return self._lower_corner
|
||||
|
||||
@property
|
||||
def upper_corner(self):
|
||||
return self._upper_corner
|
||||
|
||||
def city_object(self, name) -> Union[CityObject, None]:
|
||||
for c in self.city_objects:
|
||||
if c.name == name:
|
||||
return c
|
||||
return None
|
||||
|
||||
@property
|
||||
def srs_name(self):
|
||||
return self._srs_name
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
@name.setter
|
||||
def name(self, value):
|
||||
self._name = value
|
||||
|
193
city_model_structure/city_object.py
Normal file
193
city_model_structure/city_object.py
Normal file
|
@ -0,0 +1,193 @@
|
|||
from matplotlib import pylab
|
||||
from city_model_structure.polyhedron import Polyhedron
|
||||
from city_model_structure.thermal_zone import ThermalZone
|
||||
from city_model_structure.thermal_boundary import ThermalBoundary
|
||||
from city_model_structure.surface import Surface
|
||||
from shapely import ops
|
||||
from shapely.geometry import MultiPolygon
|
||||
import numpy as np
|
||||
from pathlib import Path
|
||||
import matplotlib.patches as patches
|
||||
from helpers.geometry import Geometry
|
||||
from city_model_structure.usage_zone import UsageZone
|
||||
from typing import Union, List
|
||||
|
||||
|
||||
class CityObject:
|
||||
def __init__(self, name, lod, surfaces, terrains, year_of_construction, function, attic_heated=0, basement_heated=0):
|
||||
self._name = name
|
||||
self._lod = lod
|
||||
self._surfaces = surfaces
|
||||
self._polyhedron = None
|
||||
self._basement_heated = basement_heated
|
||||
self._attic_heated = attic_heated
|
||||
self._terrains = terrains
|
||||
self._year_of_construction = year_of_construction
|
||||
self._function = function
|
||||
self._geometry = Geometry()
|
||||
self._average_storey_height = None
|
||||
self._storeys_above_ground = None
|
||||
self._foot_print = None
|
||||
self._usage_zones = []
|
||||
|
||||
# ToDo: Check this for LOD4
|
||||
self._thermal_zones = []
|
||||
if self.lod < 8:
|
||||
# for lod under 4 is just one thermal zone
|
||||
self._thermal_zones.append(ThermalZone(self.surfaces))
|
||||
for t in self._thermal_zones:
|
||||
t.bounded = [ThermalBoundary(s, [t]) for s in t.surfaces]
|
||||
surface_id = 0
|
||||
for s in self._surfaces:
|
||||
s.parent(self, surface_id)
|
||||
surface_id += 1
|
||||
|
||||
@property
|
||||
def usage_zones(self) -> List[UsageZone]:
|
||||
return self._usage_zones
|
||||
|
||||
@usage_zones.setter
|
||||
def usage_zones(self, value):
|
||||
self._usage_zones = value
|
||||
|
||||
@property
|
||||
def terrains(self) -> List[Surface]:
|
||||
return self._terrains
|
||||
|
||||
@property
|
||||
def attic_heated(self):
|
||||
return self._attic_heated
|
||||
|
||||
@attic_heated.setter
|
||||
def attic_heated(self, value):
|
||||
self._attic_heated = value
|
||||
|
||||
@property
|
||||
def basement_heated(self):
|
||||
return self._basement_heated
|
||||
|
||||
@basement_heated.setter
|
||||
def basement_heated(self, value):
|
||||
self._attic_heated = value
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def lod(self):
|
||||
return self._lod
|
||||
|
||||
@property
|
||||
def surfaces(self) -> List[Surface]:
|
||||
return self._surfaces
|
||||
|
||||
def surface(self, name) -> Union[Surface, None]:
|
||||
for s in self.surfaces:
|
||||
if s.name == name:
|
||||
return s
|
||||
return None
|
||||
|
||||
@property
|
||||
def thermal_zones(self) -> List[ThermalZone]:
|
||||
return self._thermal_zones
|
||||
|
||||
@property
|
||||
def volume(self):
|
||||
if self._polyhedron is None:
|
||||
self._polyhedron = Polyhedron(self.surfaces)
|
||||
return self._polyhedron.volume
|
||||
|
||||
@property
|
||||
def heated_volume(self):
|
||||
if self._polyhedron is None:
|
||||
self._polyhedron = Polyhedron(self.surfaces)
|
||||
# ToDo: this need to be the calculated based on the basement and attic heated values
|
||||
return self._polyhedron.volume
|
||||
|
||||
def stl_export(self, path):
|
||||
if self._polyhedron is None:
|
||||
self._polyhedron = Polyhedron(self.surfaces)
|
||||
full_path = (Path(path) / (self._name + '.stl')).resolve()
|
||||
self._polyhedron.save(full_path)
|
||||
|
||||
@property
|
||||
def year_of_construction(self):
|
||||
return self._year_of_construction
|
||||
|
||||
@property
|
||||
def function(self):
|
||||
return self._function
|
||||
|
||||
@property
|
||||
def average_storey_height(self):
|
||||
return self._average_storey_height
|
||||
|
||||
@average_storey_height.setter
|
||||
def average_storey_height(self, value):
|
||||
self._average_storey_height = value
|
||||
|
||||
@property
|
||||
def storeys_above_ground(self):
|
||||
return self._storeys_above_ground
|
||||
|
||||
@storeys_above_ground.setter
|
||||
def storeys_above_ground(self, value):
|
||||
self._storeys_above_ground = value
|
||||
|
||||
@staticmethod
|
||||
def _tuple_to_point(xy_tuple):
|
||||
return [xy_tuple[0], xy_tuple[1], 0.0]
|
||||
|
||||
def _plot(self, polygon):
|
||||
points = ()
|
||||
for point_tuple in polygon.exterior.coords:
|
||||
almost_equal = False
|
||||
for point in points:
|
||||
p1 = CityObject._tuple_to_point(point)
|
||||
p2 = CityObject._tuple_to_point(point_tuple)
|
||||
if self._geometry.almost_equal(p1, p2):
|
||||
almost_equal = True
|
||||
break
|
||||
if not almost_equal:
|
||||
points = points + (point_tuple,)
|
||||
points = points + (points[0],)
|
||||
pylab.scatter([point[0] for point in points], [point[1] for point in points])
|
||||
pylab.gca().add_patch(patches.Polygon(points, closed=True, fill=True))
|
||||
pylab.grid()
|
||||
pylab.show()
|
||||
|
||||
@property
|
||||
def foot_print(self) -> Surface:
|
||||
if self._foot_print is None:
|
||||
shapelys = []
|
||||
union = None
|
||||
for surface in self.surfaces:
|
||||
if surface.shapely.is_empty or not surface.shapely.is_valid:
|
||||
continue
|
||||
shapelys.append(surface.shapely)
|
||||
union = ops.unary_union(shapelys)
|
||||
shapelys = [union]
|
||||
if type(union) == MultiPolygon:
|
||||
Exception('foot print returns a multipolygon')
|
||||
points_list = []
|
||||
for point_tuple in union.exterior.coords:
|
||||
# ToDo: should be Z 0.0 or min Z?
|
||||
point = CityObject._tuple_to_point(point_tuple)
|
||||
almost_equal = False
|
||||
for existing_point in points_list:
|
||||
if self._geometry.almost_equal(point, existing_point):
|
||||
almost_equal = True
|
||||
break
|
||||
if not almost_equal:
|
||||
points_list.append(point)
|
||||
points_list = np.reshape(points_list, len(points_list) * 3)
|
||||
points = np.array_str(points_list).replace('[', '').replace(']', '')
|
||||
self._foot_print = Surface(points, remove_last=False, is_projected=True)
|
||||
return self._foot_print
|
||||
|
||||
@property
|
||||
def max_height(self):
|
||||
if self._polyhedron is None:
|
||||
self._polyhedron = Polyhedron(self.surfaces)
|
||||
return self._polyhedron.max_z
|
38
city_model_structure/internal_gains.py
Normal file
38
city_model_structure/internal_gains.py
Normal file
|
@ -0,0 +1,38 @@
|
|||
class InternalGains:
|
||||
def __init__(self):
|
||||
self._average_internal_gain_w_m2 = None
|
||||
self._convective_fraction = None
|
||||
self._radiative_fraction = None
|
||||
self._latent_fraction = None
|
||||
|
||||
@property
|
||||
def average_internal_gain_w_m2(self):
|
||||
return self._average_internal_gain_w_m2
|
||||
|
||||
@average_internal_gain_w_m2.setter
|
||||
def average_internal_gain_w_m2(self, value):
|
||||
self._average_internal_gain_w_m2 = value
|
||||
|
||||
@property
|
||||
def convective_fraction(self):
|
||||
return self._convective_fraction
|
||||
|
||||
@convective_fraction.setter
|
||||
def convective_fraction(self, value):
|
||||
self._convective_fraction = value
|
||||
|
||||
@property
|
||||
def radiative_fraction(self):
|
||||
return self._radiative_fraction
|
||||
|
||||
@radiative_fraction.setter
|
||||
def radiative_fraction(self, value):
|
||||
self._radiative_fraction = value
|
||||
|
||||
@property
|
||||
def latent_fraction(self):
|
||||
return self._latent_fraction
|
||||
|
||||
@latent_fraction.setter
|
||||
def latent_fraction(self, value):
|
||||
self._latent_fraction = value
|
23
city_model_structure/layer.py
Normal file
23
city_model_structure/layer.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
from city_model_structure.material import Material
|
||||
|
||||
|
||||
class Layer:
|
||||
def __init__(self):
|
||||
self._material = None
|
||||
self._thickness_m = None
|
||||
|
||||
@property
|
||||
def material(self) -> Material:
|
||||
return self._material
|
||||
|
||||
@material.setter
|
||||
def material(self, value):
|
||||
self._material = value
|
||||
|
||||
@property
|
||||
def thickness_m(self):
|
||||
return self._thickness_m
|
||||
|
||||
@thickness_m.setter
|
||||
def thickness_m(self, value):
|
||||
self._thickness_m = value
|
75
city_model_structure/material.py
Normal file
75
city_model_structure/material.py
Normal file
|
@ -0,0 +1,75 @@
|
|||
class Material:
|
||||
def __init__(self):
|
||||
# ToDo: construct this class
|
||||
self._conductivity_wm_k = None
|
||||
self._specific_heat_jkg_k = None
|
||||
self._density_kg_m3 = None
|
||||
self._solar_absorptance = None
|
||||
self._thermal_absorptance = None
|
||||
self._visible_absorptance = None
|
||||
self._no_mass = False
|
||||
self._thermal_resistance_m2k_w = None
|
||||
|
||||
@property
|
||||
def conductivity_wm_k(self):
|
||||
return self._conductivity_wm_k
|
||||
|
||||
@conductivity_wm_k.setter
|
||||
def conductivity_wm_k(self, value):
|
||||
self._conductivity_wm_k = value
|
||||
|
||||
@property
|
||||
def specific_heat_jkg_k(self):
|
||||
return self._specific_heat_jkg_k
|
||||
|
||||
@specific_heat_jkg_k.setter
|
||||
def specific_heat_jkg_k(self, value):
|
||||
self._specific_heat_jkg_k = value
|
||||
|
||||
@property
|
||||
def density_kg_m3(self):
|
||||
return self._density_kg_m3
|
||||
|
||||
@density_kg_m3.setter
|
||||
def density_kg_m3(self, value):
|
||||
self._density_kg_m3 = value
|
||||
|
||||
@property
|
||||
def solar_absorptance(self):
|
||||
return self._solar_absorptance
|
||||
|
||||
@solar_absorptance.setter
|
||||
def solar_absorptance(self, value):
|
||||
self._solar_absorptance = value
|
||||
|
||||
@property
|
||||
def thermal_absorptance(self):
|
||||
return self._thermal_absorptance
|
||||
|
||||
@thermal_absorptance.setter
|
||||
def thermal_absorptance(self, value):
|
||||
self._thermal_absorptance = value
|
||||
|
||||
@property
|
||||
def visible_absorptance(self):
|
||||
return self._visible_absorptance
|
||||
|
||||
@visible_absorptance.setter
|
||||
def visible_absorptance(self, value):
|
||||
self._visible_absorptance = value
|
||||
|
||||
@property
|
||||
def no_mass(self):
|
||||
return self._no_mass
|
||||
|
||||
@no_mass.setter
|
||||
def no_mass(self, value):
|
||||
self._no_mass = value
|
||||
|
||||
@property
|
||||
def thermal_resistance_m2k_w(self):
|
||||
return self._thermal_resistance_m2k_w
|
||||
|
||||
@thermal_resistance_m2k_w.setter
|
||||
def thermal_resistance_m2k_w(self, value):
|
||||
self._thermal_resistance_m2k_w = value
|
74
city_model_structure/polyhedron.py
Normal file
74
city_model_structure/polyhedron.py
Normal file
|
@ -0,0 +1,74 @@
|
|||
import numpy as np
|
||||
import stl
|
||||
from helpers.geometry import Geometry
|
||||
|
||||
|
||||
class Polyhedron:
|
||||
def __init__(self, surfaces):
|
||||
self._surfaces = [s for s in surfaces]
|
||||
self._polygons = [s.polygon for s in surfaces]
|
||||
self._polyhedron = None
|
||||
self._volume = None
|
||||
self._faces = None
|
||||
self._vertices = None
|
||||
self._mesh = None
|
||||
self._geometry = Geometry()
|
||||
|
||||
def _position_of(self, point):
|
||||
vertices = self.vertices
|
||||
for i in range(len(vertices)):
|
||||
if self._geometry.almost_equal(vertices[i], point):
|
||||
return i
|
||||
return -1
|
||||
|
||||
@property
|
||||
def vertices(self):
|
||||
if self._vertices is None:
|
||||
vertices, self._vertices = [], []
|
||||
[vertices.extend(s.points) for s in self._surfaces]
|
||||
for v1 in vertices:
|
||||
found = False
|
||||
for v2 in self._vertices:
|
||||
found = False
|
||||
if self._geometry.almost_equal(v1, v2):
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
self._vertices.append(v1)
|
||||
self._vertices = np.asarray(self._vertices)
|
||||
return self._vertices
|
||||
|
||||
@property
|
||||
def faces(self):
|
||||
if self._faces is None:
|
||||
self._faces = []
|
||||
for s in self._surfaces:
|
||||
face = []
|
||||
points = s.points
|
||||
for p in points:
|
||||
face.append(self._position_of(p))
|
||||
self._faces.append(face)
|
||||
self._faces = np.asarray(self._faces)
|
||||
return self._faces
|
||||
|
||||
@property
|
||||
def _polyhedron_mesh(self):
|
||||
if self._mesh is None:
|
||||
self._mesh = stl.mesh.Mesh(np.zeros(self.faces.shape[0], dtype=stl.mesh.Mesh.dtype))
|
||||
for i, f in enumerate(self.faces):
|
||||
for j in range(3):
|
||||
self._mesh.vectors[i][j] = self.vertices[f[j], :]
|
||||
return self._mesh
|
||||
|
||||
@property
|
||||
def volume(self):
|
||||
if self._volume is None:
|
||||
self._volume, cog, inertia = self._polyhedron_mesh.get_mass_properties()
|
||||
return self._volume
|
||||
|
||||
@property
|
||||
def max_z(self):
|
||||
return self._polyhedron_mesh.z.max()
|
||||
|
||||
def save(self, full_path):
|
||||
self._polyhedron_mesh.save(full_path)
|
176
city_model_structure/surface.py
Normal file
176
city_model_structure/surface.py
Normal file
|
@ -0,0 +1,176 @@
|
|||
from __future__ import annotations
|
||||
import numpy as np
|
||||
import pyny3d.geoms as pn
|
||||
from helpers.geometry import Geometry
|
||||
|
||||
|
||||
class Surface:
|
||||
def __init__(self, coordinates, surface_type=None, name=None, swr='0.2', remove_last=True, is_projected=False):
|
||||
self._coordinates = coordinates
|
||||
self._type = surface_type
|
||||
self._name = name
|
||||
self._swr = swr
|
||||
self._remove_last = remove_last
|
||||
self._is_projected = is_projected
|
||||
self._geometry = Geometry()
|
||||
self._polygon = None
|
||||
self._area = None
|
||||
self._points = None
|
||||
self._points_list = None
|
||||
self._normal = None
|
||||
self._azimuth = None
|
||||
self._inclination = None
|
||||
self._area_above_ground = None
|
||||
self._area_below_ground = None
|
||||
self._parent = None
|
||||
self._shapely = None
|
||||
self._projected_surface = None
|
||||
self._global_irradiance_hour = np.zeros(8760)
|
||||
self._global_irradiance_month = np.zeros(12)
|
||||
|
||||
def parent(self, parent, surface_id):
|
||||
self._parent = parent
|
||||
self._name = str(surface_id)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
if self._name is None:
|
||||
raise Exception('surface has no name')
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def swr(self):
|
||||
return self._swr
|
||||
|
||||
@swr.setter
|
||||
def swr(self, value):
|
||||
self._swr = value
|
||||
|
||||
@property
|
||||
def points(self):
|
||||
if self._points is None:
|
||||
self._points = np.fromstring(self._coordinates, dtype=float, sep=' ')
|
||||
self._points = Geometry.to_points_matrix(self._points, self._remove_last)
|
||||
return self._points
|
||||
|
||||
@property
|
||||
def points_list(self):
|
||||
if self._points_list is None:
|
||||
s = self.points
|
||||
self._points_list = np.reshape(s, len(s) * 3)
|
||||
return self._points_list
|
||||
|
||||
@property
|
||||
def polygon(self):
|
||||
if self._polygon is None:
|
||||
try:
|
||||
self._polygon = pn.Polygon(self.points)
|
||||
except ValueError:
|
||||
# is not really a polygon but a line so just return none
|
||||
self._polygon = None
|
||||
return self._polygon
|
||||
|
||||
@property
|
||||
def area(self):
|
||||
if self._area is None:
|
||||
self._area = self.polygon.get_area()
|
||||
return self._area
|
||||
|
||||
def is_almost_same_terrain(self, terrain_points, ground_points):
|
||||
equal = 0
|
||||
for t in terrain_points:
|
||||
for g in ground_points:
|
||||
if self._geometry.almost_equal(t, g):
|
||||
equal += 1
|
||||
return equal == len(terrain_points)
|
||||
|
||||
@property
|
||||
def is_terrain(self):
|
||||
for t_points in self._parent.terrains:
|
||||
if len(t_points) == len(self.points) and self.is_almost_same_terrain(t_points, self.points):
|
||||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def area_above_ground(self):
|
||||
if self._area_above_ground is None:
|
||||
self._area_above_ground = self.area - self.area_below_ground
|
||||
return self._area_above_ground
|
||||
|
||||
@property
|
||||
def area_below_ground(self):
|
||||
if self._area_below_ground is None:
|
||||
self._area_below_ground = 0.0
|
||||
if self.is_terrain:
|
||||
self._area_below_ground = self.area
|
||||
return self._area_below_ground
|
||||
|
||||
@property
|
||||
def normal(self):
|
||||
if self._normal is None:
|
||||
points = self.points
|
||||
n = np.cross(points[1] - points[0], points[2] - points[0])
|
||||
self._normal = n / np.linalg.norm(n)
|
||||
return self._normal
|
||||
|
||||
@property
|
||||
def azimuth(self):
|
||||
if self._azimuth is None:
|
||||
normal = self.normal
|
||||
self._azimuth = np.arctan2(normal[1], normal[0])
|
||||
return self._azimuth
|
||||
|
||||
@property
|
||||
def inclination(self):
|
||||
if self._inclination is None:
|
||||
self._inclination = np.arccos(self.normal[2])
|
||||
return self._inclination
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
if self._type is None:
|
||||
grad = np.rad2deg(self.inclination)
|
||||
if 170 <= grad:
|
||||
self._type = 'Ground'
|
||||
elif 80 <= grad <= 100:
|
||||
self._type = 'Wall'
|
||||
else:
|
||||
self._type = 'Roof'
|
||||
return self._type
|
||||
|
||||
@property
|
||||
def global_irradiance_hour(self):
|
||||
return self._global_irradiance_hour
|
||||
|
||||
@global_irradiance_hour.setter
|
||||
def global_irradiance_hour(self, value):
|
||||
self._global_irradiance_hour = value
|
||||
|
||||
@property
|
||||
def global_irradiance_month(self):
|
||||
return self._global_irradiance_month
|
||||
|
||||
@global_irradiance_month.setter
|
||||
def global_irradiance_month(self, value):
|
||||
self._global_irradiance_month = value
|
||||
|
||||
@property
|
||||
def shapely(self):
|
||||
if self.polygon is None:
|
||||
return None
|
||||
if self._shapely is None:
|
||||
self._shapely = self.polygon.get_shapely()
|
||||
return self._shapely
|
||||
|
||||
@property
|
||||
def projection(self) -> Surface:
|
||||
if self._is_projected:
|
||||
return self
|
||||
if self._projected_surface is None:
|
||||
coordinates = ''
|
||||
for coordinate in self.shapely.exterior.coords:
|
||||
if coordinates != '':
|
||||
coordinates = coordinates + ' '
|
||||
coordinates = coordinates + str(coordinate[0]) + ' ' + str(coordinate[1]) + ' 0.0'
|
||||
self._projected_surface = Surface(coordinates)
|
||||
return self._projected_surface
|
132
city_model_structure/thermal_boundary.py
Normal file
132
city_model_structure/thermal_boundary.py
Normal file
|
@ -0,0 +1,132 @@
|
|||
from city_model_structure.thermal_opening import ThermalOpening
|
||||
from city_model_structure.surface import Surface
|
||||
from city_model_structure.layer import Layer
|
||||
import helpers.assumptions as assumptions
|
||||
from typing import List
|
||||
|
||||
|
||||
class ThermalBoundary:
|
||||
def __init__(self, surface, delimits):
|
||||
self._surface = surface
|
||||
self._delimits = delimits
|
||||
# ToDo: up to at least LOD2 will be just one thermal opening per Thermal boundary, review for LOD3 and LOD4
|
||||
self._thermal_openings = [ThermalOpening()]
|
||||
self._layers = None
|
||||
self._outside_solar_absorptance = None
|
||||
self._outside_thermal_absorptance = None
|
||||
self._outside_visible_absorptance = None
|
||||
self._window_ratio = None
|
||||
self._u_value = None
|
||||
self._window_area = None
|
||||
self._shortwave_reflectance = None
|
||||
|
||||
@property
|
||||
def delimits(self) -> List[Surface]:
|
||||
return self._delimits
|
||||
|
||||
@property
|
||||
def azimuth(self):
|
||||
return self._surface.azimuth
|
||||
|
||||
@property
|
||||
def inclination(self):
|
||||
return self._surface.inclination
|
||||
|
||||
@property
|
||||
def area(self):
|
||||
return self._surface.area
|
||||
|
||||
@property
|
||||
def area_above_ground(self):
|
||||
return self._surface.area_above_ground
|
||||
|
||||
@property
|
||||
def area_below_ground(self):
|
||||
return self._surface.area_below_ground
|
||||
|
||||
@property
|
||||
def outside_solar_absorptance(self):
|
||||
return self._outside_solar_absorptance
|
||||
|
||||
@outside_solar_absorptance.setter
|
||||
def outside_solar_absorptance(self, value):
|
||||
self._outside_solar_absorptance = value
|
||||
|
||||
@property
|
||||
def outside_thermal_absorptance(self):
|
||||
return self._outside_thermal_absorptance
|
||||
|
||||
@outside_thermal_absorptance.setter
|
||||
def outside_thermal_absorptance(self, value):
|
||||
self._outside_thermal_absorptance = value
|
||||
|
||||
@property
|
||||
def outside_visible_absorptance(self):
|
||||
return self._outside_visible_absorptance
|
||||
|
||||
@outside_visible_absorptance.setter
|
||||
def outside_visible_absorptance(self, value):
|
||||
self._outside_visible_absorptance = value
|
||||
|
||||
@property
|
||||
def thermal_openings(self) -> List[ThermalOpening]:
|
||||
return self._thermal_openings
|
||||
|
||||
@thermal_openings.setter
|
||||
def thermal_openings(self, value):
|
||||
self._thermal_openings = value
|
||||
|
||||
@property
|
||||
def layers(self) -> List[Layer]:
|
||||
return self._layers
|
||||
|
||||
@layers.setter
|
||||
def layers(self, value):
|
||||
self._layers = value
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return self._surface.type
|
||||
|
||||
@property
|
||||
def window_ratio(self):
|
||||
return self._window_ratio
|
||||
|
||||
@window_ratio.setter
|
||||
def window_ratio(self, value):
|
||||
self._window_ratio = value
|
||||
|
||||
@property
|
||||
def window_area(self):
|
||||
if self._window_area is None:
|
||||
try:
|
||||
self._window_area = float(self._surface.area) * float(self.window_ratio)
|
||||
except TypeError:
|
||||
raise Exception('Window ratio is not defined or invalid surface area')
|
||||
return self._window_area
|
||||
|
||||
@property
|
||||
def u_value(self):
|
||||
if self._u_value is None:
|
||||
h_i = assumptions.h_i
|
||||
h_e = assumptions.h_e
|
||||
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_m2k_w)
|
||||
else:
|
||||
r_value = r_value + float(layer.material.conductivity_wm_k)/float(layer.thickness_m)
|
||||
self._u_value = 1.0/r_value
|
||||
except TypeError:
|
||||
raise Exception('Constructions layers are not initialized')
|
||||
return self._u_value
|
||||
|
||||
@property
|
||||
def shortwave_reflectance(self):
|
||||
if self._shortwave_reflectance is None:
|
||||
try:
|
||||
self._shortwave_reflectance = 1.0 - float(self.outside_solar_absorptance)
|
||||
except TypeError:
|
||||
raise Exception('Outside solar absorptance is not initialized')
|
||||
return self._shortwave_reflectance
|
90
city_model_structure/thermal_opening.py
Normal file
90
city_model_structure/thermal_opening.py
Normal file
|
@ -0,0 +1,90 @@
|
|||
import helpers.assumptions as assumptions
|
||||
|
||||
|
||||
class ThermalOpening:
|
||||
def __init__(self):
|
||||
self._area = None
|
||||
self._openable_ratio = None
|
||||
self._conductivity_w_mk = None
|
||||
self._frame_ratio = assumptions.frame_ratio
|
||||
self._g_value = None
|
||||
self._thickness_m = None
|
||||
self._inside_reflectance = None
|
||||
self._outside_reflectance = None
|
||||
self._u_value = None
|
||||
|
||||
@property
|
||||
def area(self):
|
||||
return self._area
|
||||
|
||||
@area.setter
|
||||
def area(self, value):
|
||||
self._area = value
|
||||
|
||||
@property
|
||||
def openable_ratio(self):
|
||||
raise Exception('Not implemented')
|
||||
|
||||
@openable_ratio.setter
|
||||
def openable_ratio(self, value):
|
||||
raise Exception('Not implemented')
|
||||
|
||||
@property
|
||||
def conductivity_w_mk(self):
|
||||
return self._conductivity_w_mk
|
||||
|
||||
@conductivity_w_mk.setter
|
||||
def conductivity_w_mk(self, value):
|
||||
self._conductivity_w_mk = value
|
||||
|
||||
@property
|
||||
def frame_ratio(self):
|
||||
return self._frame_ratio
|
||||
|
||||
@frame_ratio.setter
|
||||
def frame_ratio(self, value):
|
||||
self._frame_ratio = value
|
||||
|
||||
@property
|
||||
def g_value(self):
|
||||
return self._g_value
|
||||
|
||||
@g_value.setter
|
||||
def g_value(self, value):
|
||||
self._g_value = value
|
||||
|
||||
@property
|
||||
def thickness_m(self):
|
||||
return self._thickness_m
|
||||
|
||||
@thickness_m.setter
|
||||
def thickness_m(self, value):
|
||||
self._thickness_m = value
|
||||
|
||||
@property
|
||||
def inside_reflectance(self):
|
||||
return self._inside_reflectance
|
||||
|
||||
@inside_reflectance.setter
|
||||
def inside_reflectance(self, value):
|
||||
self._inside_reflectance = value
|
||||
|
||||
@property
|
||||
def outside_reflectance(self):
|
||||
return self._outside_reflectance
|
||||
|
||||
@outside_reflectance.setter
|
||||
def outside_reflectance(self, value):
|
||||
self._outside_reflectance = value
|
||||
|
||||
@property
|
||||
def u_value(self):
|
||||
if self._u_value is None:
|
||||
try:
|
||||
h_i = assumptions.h_i
|
||||
h_e = assumptions.h_e
|
||||
r_value = 1 / h_i + 1 / h_e + float(self.conductivity_w_mk) / float(self.thickness_m)
|
||||
self._u_value = 1 / r_value
|
||||
except TypeError:
|
||||
Exception('Thermal opening is not initialized')
|
||||
return self._u_value
|
86
city_model_structure/thermal_zone.py
Normal file
86
city_model_structure/thermal_zone.py
Normal file
|
@ -0,0 +1,86 @@
|
|||
from typing import List
|
||||
from city_model_structure.thermal_boundary import ThermalBoundary
|
||||
|
||||
|
||||
class ThermalZone:
|
||||
def __init__(self, surfaces, heated=True, cooled=True):
|
||||
self._surfaces = surfaces
|
||||
self._floor_area = None
|
||||
self._bounded = None
|
||||
self._heated = heated
|
||||
self._cooled = cooled
|
||||
self._additional_thermal_bridge_u_value = None
|
||||
self._effective_thermal_capacity = None
|
||||
self._indirectly_heated_area_ratio = None
|
||||
self._infiltration_rate_system_on = None
|
||||
self._infiltration_rate_system_off = None
|
||||
|
||||
@property
|
||||
def heated(self):
|
||||
return self._heated
|
||||
|
||||
@property
|
||||
def cooled(self):
|
||||
return self._cooled
|
||||
|
||||
@property
|
||||
def floor_area(self):
|
||||
if self._floor_area is None:
|
||||
self._floor_area = 0
|
||||
for s in self._surfaces:
|
||||
if s.type == 'Ground':
|
||||
self._floor_area += s.area
|
||||
return self._floor_area
|
||||
|
||||
@property
|
||||
def bounded(self) -> List[ThermalBoundary]:
|
||||
return self._bounded
|
||||
|
||||
@bounded.setter
|
||||
def bounded(self, value):
|
||||
self._bounded = value
|
||||
|
||||
@property
|
||||
def surfaces(self):
|
||||
return self._surfaces
|
||||
|
||||
@property
|
||||
def additional_thermal_bridge_u_value(self):
|
||||
return self._additional_thermal_bridge_u_value
|
||||
|
||||
@additional_thermal_bridge_u_value.setter
|
||||
def additional_thermal_bridge_u_value(self, value):
|
||||
self._additional_thermal_bridge_u_value = value
|
||||
|
||||
@property
|
||||
def effective_thermal_capacity(self):
|
||||
return self._effective_thermal_capacity
|
||||
|
||||
@effective_thermal_capacity.setter
|
||||
def effective_thermal_capacity(self, value):
|
||||
self._effective_thermal_capacity = value
|
||||
|
||||
@property
|
||||
def indirectly_heated_area_ratio(self):
|
||||
return self._indirectly_heated_area_ratio
|
||||
|
||||
@indirectly_heated_area_ratio.setter
|
||||
def indirectly_heated_area_ratio(self, value):
|
||||
self._indirectly_heated_area_ratio = value
|
||||
|
||||
@property
|
||||
def infiltration_rate_system_on(self):
|
||||
return self._infiltration_rate_system_on
|
||||
|
||||
@infiltration_rate_system_on.setter
|
||||
def infiltration_rate_system_on(self, value):
|
||||
self._infiltration_rate_system_on = value
|
||||
|
||||
@property
|
||||
def infiltration_rate_system_off(self):
|
||||
return self._infiltration_rate_system_off
|
||||
|
||||
@infiltration_rate_system_off.setter
|
||||
def infiltration_rate_system_off(self, value):
|
||||
self._infiltration_rate_system_off = value
|
||||
|
78
city_model_structure/usage_zone.py
Normal file
78
city_model_structure/usage_zone.py
Normal file
|
@ -0,0 +1,78 @@
|
|||
from city_model_structure.internal_gains import InternalGains
|
||||
from typing import List
|
||||
|
||||
|
||||
class UsageZone:
|
||||
def __init__(self):
|
||||
self._usage = None
|
||||
self._internal_gains = None
|
||||
self._heating_setpoint = None
|
||||
self._heating_setback = None
|
||||
self._cooling_setpoint = None
|
||||
self._hours_day = None
|
||||
self._days_year = None
|
||||
self._mechanical_air_change = None
|
||||
|
||||
@property
|
||||
def internal_gains(self) -> List[InternalGains]:
|
||||
return self._internal_gains
|
||||
|
||||
@internal_gains.setter
|
||||
def internal_gains(self, value):
|
||||
self._internal_gains = value
|
||||
|
||||
@property
|
||||
def heating_setpoint(self):
|
||||
return self._heating_setpoint
|
||||
|
||||
@heating_setpoint.setter
|
||||
def heating_setpoint(self, value):
|
||||
self._heating_setpoint = value
|
||||
|
||||
@property
|
||||
def heating_setback(self):
|
||||
return self._heating_setback
|
||||
|
||||
@heating_setback.setter
|
||||
def heating_setback(self, value):
|
||||
self._heating_setback = value
|
||||
|
||||
@property
|
||||
def cooling_setpoint(self):
|
||||
return self._cooling_setpoint
|
||||
|
||||
@cooling_setpoint.setter
|
||||
def cooling_setpoint(self, value):
|
||||
self._cooling_setpoint = value
|
||||
|
||||
@property
|
||||
def hours_day(self):
|
||||
return self._hours_day
|
||||
|
||||
@hours_day.setter
|
||||
def hours_day(self, value):
|
||||
self._hours_day = value
|
||||
|
||||
@property
|
||||
def days_year(self):
|
||||
return self._days_year
|
||||
|
||||
@days_year.setter
|
||||
def days_year(self, value):
|
||||
self._days_year = value
|
||||
|
||||
@property
|
||||
def mechanical_air_change(self):
|
||||
return self._mechanical_air_change
|
||||
|
||||
@mechanical_air_change.setter
|
||||
def mechanical_air_change(self, value):
|
||||
self._mechanical_air_change = value
|
||||
|
||||
@property
|
||||
def usage(self):
|
||||
return self._usage
|
||||
|
||||
@usage.setter
|
||||
def usage(self, value):
|
||||
self._usage = value
|
70
city_model_structure/window.py
Normal file
70
city_model_structure/window.py
Normal file
|
@ -0,0 +1,70 @@
|
|||
class Window:
|
||||
def __init__(self):
|
||||
# ToDo: construct this class
|
||||
self._conductivity_wm_k = None
|
||||
self._solar_transmittance_at_normal_incidence = None
|
||||
self._front_side_solar_reflectance_at_normal_incidence = None
|
||||
self._back_side_solar_reflectance_at_normal_incidence = None
|
||||
self._frame_ratio = None
|
||||
self._thickness_m = None
|
||||
self._shgc = None
|
||||
|
||||
@property
|
||||
def conductivity_wm_k(self):
|
||||
return self._conductivity_wm_k
|
||||
|
||||
@conductivity_wm_k.setter
|
||||
def conductivity_wm_k(self, value):
|
||||
self._conductivity_wm_k = value
|
||||
|
||||
@property
|
||||
def solar_transmittance_at_normal_incidence(self):
|
||||
return self._solar_transmittance_at_normal_incidence
|
||||
|
||||
@solar_transmittance_at_normal_incidence.setter
|
||||
def solar_transmittance_at_normal_incidence(self, value):
|
||||
self._solar_transmittance_at_normal_incidence = value
|
||||
|
||||
@property
|
||||
def front_side_solar_reflectance_at_normal_incidence(self):
|
||||
return self._front_side_solar_reflectance_at_normal_incidence
|
||||
|
||||
@front_side_solar_reflectance_at_normal_incidence.setter
|
||||
def front_side_solar_reflectance_at_normal_incidence(self, value):
|
||||
self._front_side_solar_reflectance_at_normal_incidence = value
|
||||
|
||||
@property
|
||||
def back_side_solar_reflectance_at_normal_incidence(self):
|
||||
return self._back_side_solar_reflectance_at_normal_incidence
|
||||
|
||||
@back_side_solar_reflectance_at_normal_incidence.setter
|
||||
def back_side_solar_reflectance_at_normal_incidence(self, value):
|
||||
self._back_side_solar_reflectance_at_normal_incidence = value
|
||||
|
||||
@property
|
||||
def frame_ratio(self):
|
||||
return self._frame_ratio
|
||||
|
||||
@frame_ratio.setter
|
||||
def frame_ratio(self, value):
|
||||
self._frame_ratio = value
|
||||
|
||||
@frame_ratio.setter
|
||||
def frame_ratio(self, value):
|
||||
self._frame_ratio = value
|
||||
|
||||
@property
|
||||
def thickness_m(self):
|
||||
return self._thickness_m
|
||||
|
||||
@thickness_m.setter
|
||||
def thickness_m(self, value):
|
||||
self._thickness_m = value
|
||||
|
||||
@property
|
||||
def shgc(self):
|
||||
return self._shgc
|
||||
|
||||
@shgc.setter
|
||||
def shgc(self, value):
|
||||
self._shgc = value
|
24
geometry/geometry_factory.py
Normal file
24
geometry/geometry_factory.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
from geometry.geometry_feeders.city_gml import CityGml
|
||||
from city_model_structure.city import City
|
||||
|
||||
|
||||
class GeometryFactory:
|
||||
def __init__(self, file_type, path):
|
||||
self._file_type = file_type.lower()
|
||||
self._path = path
|
||||
|
||||
@property
|
||||
def citygml(self):
|
||||
return CityGml(self._path).city
|
||||
|
||||
@property
|
||||
def geojson(self):
|
||||
raise Exception('Not implemented')
|
||||
|
||||
@property
|
||||
def bim(self):
|
||||
raise Exception('Not implemented')
|
||||
|
||||
@property
|
||||
def city(self) -> City:
|
||||
return getattr(self, self._file_type, lambda: None)
|
106
geometry/geometry_feeders/city_gml.py
Normal file
106
geometry/geometry_feeders/city_gml.py
Normal file
|
@ -0,0 +1,106 @@
|
|||
import xmltodict
|
||||
import numpy as np
|
||||
from city_model_structure.city import City
|
||||
from city_model_structure.city_object import CityObject
|
||||
from city_model_structure.surface import Surface
|
||||
from helpers.geometry import Geometry
|
||||
|
||||
|
||||
class CityGml:
|
||||
def __init__(self, path):
|
||||
self._city = None
|
||||
with open(path) as gml:
|
||||
# Clean the namespaces is an important task to prevent wrong ns:field due poor citygml implementations
|
||||
self._gml = xmltodict.parse(gml.read(), process_namespaces=True, xml_attribs=True, namespaces={
|
||||
'http://www.opengis.net/gml': None,
|
||||
'http://www.w3.org/2001/XMLSchema-instance': None,
|
||||
'urn:oasis:names:tc:ciq:xsdschema:xAL:2.0': None,
|
||||
'http://www.w3.org/1999/xlink': None,
|
||||
'http://www.opengis.net/citygml/relief/2.0': None,
|
||||
'http://www.opengis.net/citygml/building/2.0': None,
|
||||
'http://www.opengis.net/citygml/building/2.0 http://schemas.opengis.net/citygml/building/2.0/building.xsd '
|
||||
'http://www.opengis.net/citygml/relief/2.0 http://schemas.opengis.net/citygml/relief/2.0/relief.xsd" '
|
||||
'xmlns="http://www.opengis.net/citygml/2.0': None,
|
||||
'http://www.opengis.net/citygml/2.0': None
|
||||
}, force_list=('cityObjectMember', 'curveMember'))
|
||||
self._cityObjects = None
|
||||
self._geometry = Geometry()
|
||||
envelope = self._gml['CityModel']['boundedBy']['Envelope']
|
||||
if '#text' in envelope['lowerCorner']:
|
||||
self._lower_corner = np.fromstring(envelope['lowerCorner']['#text'], dtype=float, sep=' ')
|
||||
self._upper_corner = np.fromstring(envelope['upperCorner']['#text'], dtype=float, sep=' ')
|
||||
else:
|
||||
self._lower_corner = np.fromstring(envelope['lowerCorner'], dtype=float, sep=' ')
|
||||
self._upper_corner = np.fromstring(envelope['upperCorner'], dtype=float, sep=' ')
|
||||
|
||||
self._srs_name = envelope['@srsName']
|
||||
|
||||
@property
|
||||
def content(self):
|
||||
return self._gml
|
||||
|
||||
@property
|
||||
def city(self):
|
||||
if self._city is None:
|
||||
city_objects = []
|
||||
for o in self._gml['CityModel']['cityObjectMember']:
|
||||
lod = 0
|
||||
if 'lod1Solid' in o['Building']:
|
||||
lod += 1
|
||||
if 'lod2Solid' in o['Building']:
|
||||
lod += 2
|
||||
if 'lod3Solid' in o['Building']:
|
||||
lod += 4
|
||||
if 'lod4Solid' in o['Building']:
|
||||
lod += 8
|
||||
# ToDo: this is specific for Lod1 need to be modeled for higher lod's and lod combinations
|
||||
name = o['Building']['@id']
|
||||
lod_str = 'lod' + str(lod) + 'Solid'
|
||||
lod_terrain_str = 'lod' + str(lod) + 'TerrainIntersection'
|
||||
try:
|
||||
surfaces = [Surface(s['Polygon']['exterior']['LinearRing']['posList']['#text'])
|
||||
for s in o['Building'][lod_str]['Solid']['exterior']['CompositeSurface']['surfaceMember']]
|
||||
except TypeError:
|
||||
surfaces = [Surface(s['Polygon']['exterior']['LinearRing']['posList'])
|
||||
for s in o['Building'][lod_str]['Solid']['exterior']['CompositeSurface']['surfaceMember']]
|
||||
|
||||
if lod_terrain_str in o['Building']:
|
||||
try:
|
||||
curves = [c['LineString']['posList']['#text']
|
||||
for c in o['Building'][lod_terrain_str]['MultiCurve']['curveMember']]
|
||||
except TypeError:
|
||||
curves = [c['LineString']['posList']
|
||||
for c in o['Building'][lod_terrain_str]['MultiCurve']['curveMember']]
|
||||
|
||||
terrains = []
|
||||
for curve in curves:
|
||||
curve_points = np.fromstring(curve, dtype=float, sep=' ')
|
||||
curve_points = self._geometry.to_points_matrix(curve_points, True)
|
||||
terrains.append(curve_points)
|
||||
else:
|
||||
|
||||
terrains = []
|
||||
for s in surfaces:
|
||||
ground = True
|
||||
ground_points = []
|
||||
for row in s.points:
|
||||
# all surface vertex are in the lower z
|
||||
ground_point = [row[0], row[1], self._lower_corner[2]]
|
||||
ground_points = np.concatenate((ground_points, ground_point), axis=None)
|
||||
ground = ground and self._geometry.almost_equal(row, ground_point)
|
||||
if ground:
|
||||
ground_points = self._geometry.to_points_matrix(ground_points)
|
||||
# Do i need to remove the duplicated?
|
||||
terrains.append(ground_points)
|
||||
year_of_construction = None
|
||||
function = None
|
||||
if 'yearOfConstruction' in o['Building']:
|
||||
year_of_construction = o['Building']['yearOfConstruction']
|
||||
if 'function' in o['Building']:
|
||||
function = o['Building']['function']
|
||||
|
||||
city_objects.append(CityObject(name, lod, surfaces, terrains, year_of_construction, function))
|
||||
self._city = City(self._lower_corner, self._upper_corner, city_objects, self._srs_name)
|
||||
return self._city
|
||||
|
||||
|
27
physics/physics_factory.py
Normal file
27
physics/physics_factory.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
from physics.physics_feeders.us_new_york_city_physics_parameters import UsNewYorkCityPhysicsParameters
|
||||
from physics.physics_feeders.us_physics_parameters import UsPhysicsParameters
|
||||
|
||||
|
||||
class PhysicsFactory:
|
||||
def __init__(self, handler, city):
|
||||
self._handler = handler.lower().replace(' ', '_')
|
||||
self._city = city
|
||||
self.factory()
|
||||
|
||||
def us_new_york_city(self):
|
||||
UsNewYorkCityPhysicsParameters(self._city)
|
||||
|
||||
def us(self):
|
||||
UsPhysicsParameters(self._city)
|
||||
|
||||
def ca(self):
|
||||
raise Exception('Not implemented')
|
||||
|
||||
def de(self):
|
||||
raise Exception('Not implemented')
|
||||
|
||||
def es(self):
|
||||
raise Exception('Not implemented')
|
||||
|
||||
def factory(self):
|
||||
getattr(self, self._handler, lambda: None)()
|
228
physics/physics_feeders/helpers/pluto_to_function.py
Normal file
228
physics/physics_feeders/helpers/pluto_to_function.py
Normal file
|
@ -0,0 +1,228 @@
|
|||
class PlutoToFunction:
|
||||
|
||||
building_function = {
|
||||
'A0': 'single family house',
|
||||
'A1': 'single family house',
|
||||
'A2': 'single family house',
|
||||
'A3': 'single family house',
|
||||
'A4': 'single family house',
|
||||
'A5': 'single family house',
|
||||
'A6': 'single family house',
|
||||
'A7': 'single family house',
|
||||
'A8': 'single family house',
|
||||
'A9': 'single family house',
|
||||
'B1': 'multifamily house',
|
||||
'B2': 'multifamily house',
|
||||
'B3': 'multifamily house',
|
||||
'B9': 'multifamily house',
|
||||
'C0': 'residential',
|
||||
'C1': 'residential',
|
||||
'C2': 'residential',
|
||||
'C3': 'residential',
|
||||
'C4': 'residential',
|
||||
'C5': 'residential',
|
||||
'C6': 'residential',
|
||||
'C7': 'residential',
|
||||
'C8': 'residential',
|
||||
'C9': 'residential',
|
||||
'D0': 'residential',
|
||||
'D1': 'residential',
|
||||
'D2': 'residential',
|
||||
'D3': 'residential',
|
||||
'D4': 'residential',
|
||||
'D5': 'residential',
|
||||
'D6': 'residential',
|
||||
'D7': 'residential',
|
||||
'D8': 'residential',
|
||||
'D9': 'residential',
|
||||
'E1': 'warehouse',
|
||||
'E3': 'warehouse',
|
||||
'E4': 'warehouse',
|
||||
'E5': 'warehouse',
|
||||
'E7': 'warehouse',
|
||||
'E9': 'warehouse',
|
||||
'F1': 'warehouse',
|
||||
'F2': 'warehouse',
|
||||
'F4': 'warehouse',
|
||||
'F5': 'warehouse',
|
||||
'F8': 'warehouse',
|
||||
'F9': 'warehouse',
|
||||
'G0': 'office',
|
||||
'G1': 'office',
|
||||
'G2': 'office',
|
||||
'G3': 'office',
|
||||
'G4': 'office',
|
||||
'G5': 'office',
|
||||
'G6': 'office',
|
||||
'G7': 'office',
|
||||
'G8': 'office',
|
||||
'G9': 'office',
|
||||
'H1': 'hotel',
|
||||
'H2': 'hotel',
|
||||
'H3': 'hotel',
|
||||
'H4': 'hotel',
|
||||
'H5': 'hotel',
|
||||
'H6': 'hotel',
|
||||
'H7': 'hotel',
|
||||
'H8': 'hotel',
|
||||
'H9': 'hotel',
|
||||
'HB': 'hotel',
|
||||
'HH': 'hotel',
|
||||
'HR': 'hotel',
|
||||
'HS': 'hotel',
|
||||
'I1': 'hospital',
|
||||
'I2': 'outpatient',
|
||||
'I3': 'outpatient',
|
||||
'I4': 'residential',
|
||||
'I5': 'outpatient',
|
||||
'I6': 'outpatient',
|
||||
'I7': 'outpatient',
|
||||
'I9': 'outpatient',
|
||||
'J1': 'large office',
|
||||
'J2': 'large office',
|
||||
'J3': 'large office',
|
||||
'J4': 'large office',
|
||||
'J5': 'large office',
|
||||
'J6': 'large office',
|
||||
'J7': 'large office',
|
||||
'J8': 'large office',
|
||||
'J9': 'large office',
|
||||
'K1': 'strip mall',
|
||||
'K2': 'strip mall',
|
||||
'K3': 'strip mall',
|
||||
'K4': 'residential',
|
||||
'K5': 'restaurant',
|
||||
'K6': 'commercial',
|
||||
'K7': 'commercial',
|
||||
'K8': 'commercial',
|
||||
'K9': 'commercial',
|
||||
'L1': 'residential',
|
||||
'L2': 'residential',
|
||||
'L3': 'residential',
|
||||
'L8': 'residential',
|
||||
'L9': 'residential',
|
||||
'M1': 'large office',
|
||||
'M2': 'large office',
|
||||
'M3': 'large office',
|
||||
'M4': 'large office',
|
||||
'M9': 'large office',
|
||||
'N1': 'residential',
|
||||
'N2': 'residential',
|
||||
'N3': 'residential',
|
||||
'N4': 'residential',
|
||||
'N9': 'residential',
|
||||
'O1': 'office',
|
||||
'O2': 'office',
|
||||
'O3': 'office',
|
||||
'O4': 'office',
|
||||
'O5': 'office',
|
||||
'O6': 'office',
|
||||
'O7': 'office',
|
||||
'O8': 'office',
|
||||
'O9': 'office',
|
||||
'P1': 'large office',
|
||||
'P2': 'hotel',
|
||||
'P3': 'office',
|
||||
'P4': 'office',
|
||||
'P5': 'office',
|
||||
'P6': 'office',
|
||||
'P7': 'large office',
|
||||
'P8': 'large office',
|
||||
'P9': 'office',
|
||||
'Q0': 'office',
|
||||
'Q1': 'office',
|
||||
'Q2': 'office',
|
||||
'Q3': 'office',
|
||||
'Q4': 'office',
|
||||
'Q5': 'office',
|
||||
'Q6': 'office',
|
||||
'Q7': 'office',
|
||||
'Q8': 'office',
|
||||
'Q9': 'office',
|
||||
'R0': 'residential',
|
||||
'R1': 'residential',
|
||||
'R2': 'residential',
|
||||
'R3': 'residential',
|
||||
'R4': 'residential',
|
||||
'R5': 'residential',
|
||||
'R6': 'residential',
|
||||
'R7': 'residential',
|
||||
'R8': 'residential',
|
||||
'R9': 'residential',
|
||||
'RA': 'residential',
|
||||
'RB': 'residential',
|
||||
'RC': 'residential',
|
||||
'RD': 'residential',
|
||||
'RG': 'residential',
|
||||
'RH': 'residential',
|
||||
'RI': 'residential',
|
||||
'RK': 'residential',
|
||||
'RM': 'residential',
|
||||
'RR': 'residential',
|
||||
'RS': 'residential',
|
||||
'RW': 'residential',
|
||||
'RX': 'residential',
|
||||
'RZ': 'residential',
|
||||
'S0': 'residential',
|
||||
'S1': 'residential',
|
||||
'S2': 'residential',
|
||||
'S3': 'residential',
|
||||
'S4': 'residential',
|
||||
'S5': 'residential',
|
||||
'S9': 'residential',
|
||||
'T1': 'na',
|
||||
'T2': 'na',
|
||||
'T9': 'na',
|
||||
'U0': 'warehouse',
|
||||
'U1': 'warehouse',
|
||||
'U2': 'warehouse',
|
||||
'U3': 'warehouse',
|
||||
'U4': 'warehouse',
|
||||
'U5': 'warehouse',
|
||||
'U6': 'warehouse',
|
||||
'U7': 'warehouse',
|
||||
'U8': 'warehouse',
|
||||
'U9': 'warehouse',
|
||||
'V0': 'na',
|
||||
'V1': 'na',
|
||||
'V2': 'na',
|
||||
'V3': 'na',
|
||||
'V4': 'na',
|
||||
'V5': 'na',
|
||||
'V6': 'na',
|
||||
'V7': 'na',
|
||||
'V8': 'na',
|
||||
'V9': 'na',
|
||||
'W1': 'primary school',
|
||||
'W2': 'primary school',
|
||||
'W3': 'secondary school',
|
||||
'W4': 'secondary school',
|
||||
'W5': 'secondary school',
|
||||
'W6': 'secondary school',
|
||||
'W7': 'secondary school',
|
||||
'W8': 'primary school',
|
||||
'W9': 'secondary school',
|
||||
'Y1': 'large office',
|
||||
'Y2': 'large office',
|
||||
'Y3': 'large office',
|
||||
'Y4': 'large office',
|
||||
'Y5': 'large office',
|
||||
'Y6': 'large office',
|
||||
'Y7': 'large office',
|
||||
'Y8': 'large office',
|
||||
'Y9': 'large office',
|
||||
'Z0': 'na',
|
||||
'Z1': 'large office',
|
||||
'Z2': 'na',
|
||||
'Z3': 'na',
|
||||
'Z4': 'na',
|
||||
'Z5': 'na',
|
||||
'Z6': 'na',
|
||||
'Z7': 'na',
|
||||
'Z8': 'na',
|
||||
'Z9': 'na'
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def function(pluto):
|
||||
return PlutoToFunction.building_function[pluto]
|
57
physics/physics_feeders/helpers/us_to_library_types.py
Normal file
57
physics/physics_feeders/helpers/us_to_library_types.py
Normal file
|
@ -0,0 +1,57 @@
|
|||
class UsToLibraryTypes(object):
|
||||
standards = {
|
||||
'ASHRAE Std189': 1,
|
||||
'ASHRAE 90.1-2004': 2
|
||||
}
|
||||
|
||||
reference_city_climate_zone = {
|
||||
'Miami': 'ASHRAE_2004:1A',
|
||||
'Houston': 'ASHRAE_2004:2A',
|
||||
'Phoenix': 'ASHRAE_2004:2B',
|
||||
'Atlanta': 'ASHRAE_2004:3A',
|
||||
'Los Angeles': 'ASHRAE_2004:3B',
|
||||
'Las Vegas': 'ASHRAE_2004:3B',
|
||||
'San Francisco': 'ASHRAE_2004:3C',
|
||||
'Baltimore': 'ASHRAE_2004:4A',
|
||||
'Albuquerque': 'ASHRAE_2004:4B',
|
||||
'Seattle': 'ASHRAE_2004:4C',
|
||||
'Chicago': 'ASHRAE_2004:5A',
|
||||
'Boulder': 'ASHRAE_2004:5B',
|
||||
'Minneapolis': 'ASHRAE_2004:6A',
|
||||
'Helena': 'ASHRAE_2004:6B',
|
||||
'Duluth': 'ASHRAE_2004:7A',
|
||||
'Fairbanks': 'ASHRAE_2004:8A'
|
||||
}
|
||||
|
||||
window_types = ['window', 'door', 'skylight']
|
||||
|
||||
construction_types = {
|
||||
'Wall': 'exterior wall',
|
||||
'interior wall': 'interior wall',
|
||||
'ground wall': 'ground wall',
|
||||
'Ground': 'exterior slab',
|
||||
'attic floor': 'attic floor',
|
||||
'interior slab': 'interior slab',
|
||||
'Roof': 'roof'
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def yoc_to_standard(year_of_construction):
|
||||
if int(year_of_construction) < 2009:
|
||||
standard = 'ASHRAE 90.1_2004'
|
||||
else:
|
||||
standard = 'ASHRAE 189.1_2009'
|
||||
return standard
|
||||
|
||||
@staticmethod
|
||||
def city_to_reference_city(city):
|
||||
# ToDo: Dummy function that need to be implemented
|
||||
reference_city = 'Baltimore'
|
||||
if city is not None:
|
||||
reference_city = 'Baltimore'
|
||||
return reference_city
|
||||
|
||||
@staticmethod
|
||||
def city_to_climate_zone(city):
|
||||
reference_city = UsToLibraryTypes.city_to_reference_city(city)
|
||||
return UsToLibraryTypes.reference_city_climate_zone[reference_city]
|
109
physics/physics_feeders/us_base_physics_parameters.py
Normal file
109
physics/physics_feeders/us_base_physics_parameters.py
Normal file
|
@ -0,0 +1,109 @@
|
|||
import xmltodict
|
||||
from city_model_structure.layer import Layer
|
||||
from city_model_structure.material import Material
|
||||
from pathlib import Path
|
||||
from physics.physics_feeders.helpers.us_to_library_types import UsToLibraryTypes
|
||||
|
||||
|
||||
class UsBasePhysicsParameters:
|
||||
def __init__(self, climate_zone, city_objects, function_to_type):
|
||||
self._climate_zone = climate_zone
|
||||
self._city_objects = city_objects
|
||||
|
||||
# load US Library
|
||||
path = str(Path.cwd() / 'data/physics/us_constructions.xml')
|
||||
with open(path) as xml:
|
||||
self._library = xmltodict.parse(xml.read(), force_list='layer')
|
||||
|
||||
# load US Archetypes
|
||||
path = str(Path.cwd() / 'data/physics/us_archetypes.xml')
|
||||
with open(path) as xml:
|
||||
self._archetypes = xmltodict.parse(xml.read(), force_list='layer')
|
||||
for city_object in self._city_objects:
|
||||
building_type = function_to_type(city_object.function)
|
||||
if building_type is None:
|
||||
return
|
||||
archetype = self.search_archetype(building_type,
|
||||
UsToLibraryTypes.yoc_to_standard(city_object.year_of_construction),
|
||||
self._climate_zone)
|
||||
# ToDo:remove this in the future
|
||||
# ToDo: Raise WrongArchetype if not all the surface types are defined for the given city_object
|
||||
if archetype is None:
|
||||
print(building_type, UsToLibraryTypes.yoc_to_standard(city_object.year_of_construction),
|
||||
self._climate_zone)
|
||||
raise Exception('Archetype not found for building')
|
||||
|
||||
city_object.average_storey_height = archetype['average_storey_height']['#text']
|
||||
city_object.storeys_above_ground = archetype['number_of_storeys']['#text']
|
||||
|
||||
for thermal_zone in city_object.thermal_zones:
|
||||
thermal_zone.effective_thermal_capacity = archetype['thermal_capacity']['#text']
|
||||
thermal_zone.additional_thermal_bridge_u_value = archetype['extra_loses_due_to_thermal_bridges']['#text']
|
||||
thermal_zone.indirectly_heated_area_ratio = archetype['indirect_heated_ratio']['#text']
|
||||
thermal_zone.infiltration_rate_system_off = archetype['infiltration_rate_for_ventilation_system_off']['#text']
|
||||
thermal_zone.infiltration_rate_system_on = archetype['infiltration_rate_for_ventilation_system_on']['#text']
|
||||
for thermal_boundary in thermal_zone.bounded:
|
||||
construction_type = UsToLibraryTypes.construction_types[thermal_boundary.type]
|
||||
construction = UsBasePhysicsParameters.search_construction_in_archetype(archetype, construction_type)
|
||||
construction_id = construction['@id']
|
||||
c_lib = self.search_construction_type('construction', construction_id)
|
||||
if 'outside_solar_absorptance' in c_lib:
|
||||
thermal_boundary.outside_solar_absorptance = c_lib['outside_solar_absorptance']['#text']
|
||||
thermal_boundary.outside_thermal_absorptance = c_lib['outside_thermal_absorptance']['#text']
|
||||
thermal_boundary.outside_visible_absorptance = c_lib['outside_visible_absorptance']['#text']
|
||||
thermal_boundary.window_ratio = construction['window_ratio']['#text']
|
||||
thermal_boundary.layers = []
|
||||
for current_layer in c_lib['layers']['layer']:
|
||||
layer = Layer()
|
||||
if 'thickness' in current_layer:
|
||||
layer.thickness_m = current_layer['thickness']['#text']
|
||||
material_lib = self.search_construction_type('material', current_layer['material'])
|
||||
material = Material()
|
||||
if 'conductivity' in material_lib:
|
||||
material.conductivity_wm_k = material_lib['conductivity']['#text']
|
||||
material.specific_heat_jkg_k = material_lib['specific_heat']['#text']
|
||||
material.density_kg_m3 = material_lib['density']['#text']
|
||||
material.solar_absorptance = material_lib['solar_absorptance']['#text']
|
||||
material.thermal_absorptance = material_lib['thermal_absorptance']['#text']
|
||||
material.visible_absorptance = material_lib['visible_absorptance']['#text']
|
||||
material.no_mass = 'no_mass' in material_lib
|
||||
if 'thermal_resistance' in material_lib:
|
||||
material.thermal_resistance_m2k_w = material_lib['thermal_resistance']['#text']
|
||||
else:
|
||||
material.thermal_resistance_m2k_w = None
|
||||
layer.material = material
|
||||
thermal_boundary.layers.append(layer)
|
||||
for opening in thermal_boundary.thermal_openings:
|
||||
if construction['window'] is None:
|
||||
continue
|
||||
w_lib = self.search_construction_type('window', construction['window'])
|
||||
opening.area = '0.0'
|
||||
opening.conductivity_w_mk = w_lib['conductivity']['#text']
|
||||
opening.frame_ratio = w_lib['frame_ratio']['#text']
|
||||
opening.g_value = w_lib['solar_transmittance_at_normal_incidence']['#text']
|
||||
opening.thickness_m = w_lib['thickness']['#text']
|
||||
opening.inside_reflectance = 1.0-float(w_lib['back_side_solar_transmittance_at_normal_incidence']['#text'])
|
||||
opening.outside_reflectance = \
|
||||
1.0-float(w_lib['front_side_solar_transmittance_at_normal_incidence']['#text'])
|
||||
|
||||
def search_archetype(self, building_type, standard, climate_zone):
|
||||
for archetype in self._archetypes['archetypes']['archetype']:
|
||||
a_yc = str(archetype['@reference_standard'])
|
||||
a_bt = str(archetype['@building_type'])
|
||||
a_cz = str(archetype['@climate_zone'])
|
||||
if (a_yc == str(standard)) and (a_bt == str(building_type)) and (a_cz == str(climate_zone)):
|
||||
return archetype
|
||||
return None
|
||||
|
||||
def search_construction_type(self, construction_type, construction_id):
|
||||
for c_lib in self._library['library'][construction_type + 's'][construction_type]:
|
||||
if construction_id == c_lib['@id']:
|
||||
return c_lib
|
||||
raise Exception('Archetype definition contains elements that does not exist in the library')
|
||||
|
||||
@staticmethod
|
||||
def search_construction_in_archetype(archetype, construction_type):
|
||||
for construction in archetype['constructions']['construction']:
|
||||
if construction['@type'] == construction_type:
|
||||
return construction
|
||||
raise Exception('Construction type not found')
|
|
@ -0,0 +1,10 @@
|
|||
from physics.physics_feeders.us_base_physics_parameters import UsBasePhysicsParameters
|
||||
from physics.physics_feeders.helpers.pluto_to_function import PlutoToFunction as Pf
|
||||
|
||||
|
||||
class UsNewYorkCityPhysicsParameters(UsBasePhysicsParameters):
|
||||
def __init__(self, city):
|
||||
self._city = city
|
||||
climate_zone = 'ASHRAE_2004:4A'
|
||||
super().__init__(climate_zone, self._city.city_objects, Pf.function)
|
||||
|
11
physics/physics_feeders/us_physics_parameters.py
Normal file
11
physics/physics_feeders/us_physics_parameters.py
Normal file
|
@ -0,0 +1,11 @@
|
|||
from physics.physics_feeders.us_base_physics_parameters import UsBasePhysicsParameters
|
||||
from physics.physics_feeders.helpers.pluto_to_function import PlutoToFunction as Pf
|
||||
from physics.physics_feeders.helpers.us_to_library_types import UsToLibraryTypes
|
||||
|
||||
|
||||
class UsPhysicsParameters(UsBasePhysicsParameters):
|
||||
def __init__(self, city):
|
||||
self._city = city
|
||||
self._climate_zone = UsToLibraryTypes.city_to_climate_zone(city.city_name)
|
||||
super().__init__(self._climate_zone, self._city.city_objects, Pf.building_type_to_nrel)
|
||||
|
24
usage/usage_factory.py
Normal file
24
usage/usage_factory.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
from usage.usage_feeders.de_usage_parameters import DeUsageParameters
|
||||
from usage.usage_feeders.us_new_york_city_usage_parameters import UsNewYorkCityUsageParameters
|
||||
|
||||
|
||||
class UsageFactory:
|
||||
def __init__(self, handler, city):
|
||||
self._handler = handler.lower().replace(' ', '_')
|
||||
self._city = city
|
||||
self.factory()
|
||||
|
||||
def us_new_york_city(self):
|
||||
UsNewYorkCityUsageParameters(self._city)
|
||||
|
||||
def ca(self):
|
||||
raise Exception('Not implemented')
|
||||
|
||||
def de(self):
|
||||
DeUsageParameters(self._city)
|
||||
|
||||
def es(self):
|
||||
raise Exception('Not implemented')
|
||||
|
||||
def factory(self):
|
||||
getattr(self, self._handler, lambda: None)()
|
15
usage/usage_feeders/de_usage_parameters.py
Normal file
15
usage/usage_feeders/de_usage_parameters.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
import xmltodict
|
||||
from pathlib import Path
|
||||
from usage.usage_feeders.helpers.us_function_to_usage import UsFunctionToUsage
|
||||
|
||||
|
||||
class DeUsageParameters:
|
||||
def __init__(self, city_objects):
|
||||
self._city_objects = city_objects
|
||||
|
||||
# load US Library
|
||||
path = str(Path.cwd() / 'data/usage/de_library.xml')
|
||||
with open(path) as xml:
|
||||
self._library = xmltodict.parse(xml.read())
|
||||
for city_object in city_objects:
|
||||
UsFunctionToUsage.function_to_usage(city_object.function)
|
251
usage/usage_feeders/helpers/us_function_to_usage.py
Normal file
251
usage/usage_feeders/helpers/us_function_to_usage.py
Normal file
|
@ -0,0 +1,251 @@
|
|||
class UsFunctionToUsage:
|
||||
building_usage = {
|
||||
'full service restaurant': 'restaurant',
|
||||
'highrise apartment': 'residential',
|
||||
'hospital': 'health care',
|
||||
'large hotel': 'hotel',
|
||||
'large office': 'office and administration',
|
||||
'medium office': 'office and administration',
|
||||
'midrise apartment': 'residential',
|
||||
'outpatient healthcare': 'health care',
|
||||
'primary school': 'education',
|
||||
'quick service restaurant': 'restaurant',
|
||||
'secondary school': 'education',
|
||||
'small hotel': 'hotel',
|
||||
'small office': 'office and administration',
|
||||
'stand alone retail': 'retail',
|
||||
'strip mall': 'hall',
|
||||
'supermarket': 'retail',
|
||||
'warehouse': 'industry'
|
||||
}
|
||||
|
||||
building_function = {
|
||||
'A0': 'single family house',
|
||||
'A1': 'single family house',
|
||||
'A2': 'single family house',
|
||||
'A3': 'single family house',
|
||||
'A4': 'single family house',
|
||||
'A5': 'single family house',
|
||||
'A6': 'single family house',
|
||||
'A7': 'single family house',
|
||||
'A8': 'single family house',
|
||||
'A9': 'single family house',
|
||||
'B1': 'multifamily house',
|
||||
'B2': 'multifamily house',
|
||||
'B3': 'multifamily house',
|
||||
'B9': 'multifamily house',
|
||||
'C0': 'residential',
|
||||
'C1': 'residential',
|
||||
'C2': 'residential',
|
||||
'C3': 'residential',
|
||||
'C4': 'residential',
|
||||
'C5': 'residential',
|
||||
'C6': 'residential',
|
||||
'C7': 'residential',
|
||||
'C8': 'residential',
|
||||
'C9': 'residential',
|
||||
'D0': 'residential',
|
||||
'D1': 'residential',
|
||||
'D2': 'residential',
|
||||
'D3': 'residential',
|
||||
'D4': 'residential',
|
||||
'D5': 'residential',
|
||||
'D6': 'residential',
|
||||
'D7': 'residential',
|
||||
'D8': 'residential',
|
||||
'D9': 'residential',
|
||||
'E1': 'warehouse',
|
||||
'E3': 'warehouse',
|
||||
'E4': 'warehouse',
|
||||
'E5': 'warehouse',
|
||||
'E7': 'warehouse',
|
||||
'E9': 'warehouse',
|
||||
'F1': 'warehouse',
|
||||
'F2': 'warehouse',
|
||||
'F4': 'warehouse',
|
||||
'F5': 'warehouse',
|
||||
'F8': 'warehouse',
|
||||
'F9': 'warehouse',
|
||||
'G0': 'office',
|
||||
'G1': 'office',
|
||||
'G2': 'office',
|
||||
'G3': 'office',
|
||||
'G4': 'office',
|
||||
'G5': 'office',
|
||||
'G6': 'office',
|
||||
'G7': 'office',
|
||||
'G8': 'office',
|
||||
'G9': 'office',
|
||||
'H1': 'hotel',
|
||||
'H2': 'hotel',
|
||||
'H3': 'hotel',
|
||||
'H4': 'hotel',
|
||||
'H5': 'hotel',
|
||||
'H6': 'hotel',
|
||||
'H7': 'hotel',
|
||||
'H8': 'hotel',
|
||||
'H9': 'hotel',
|
||||
'HB': 'hotel',
|
||||
'HH': 'hotel',
|
||||
'HR': 'hotel',
|
||||
'HS': 'hotel',
|
||||
'I1': 'hospital',
|
||||
'I2': 'outpatient',
|
||||
'I3': 'outpatient',
|
||||
'I4': 'residential',
|
||||
'I5': 'outpatient',
|
||||
'I6': 'outpatient',
|
||||
'I7': 'outpatient',
|
||||
'I9': 'outpatient',
|
||||
'J1': 'large office',
|
||||
'J2': 'large office',
|
||||
'J3': 'large office',
|
||||
'J4': 'large office',
|
||||
'J5': 'large office',
|
||||
'J6': 'large office',
|
||||
'J7': 'large office',
|
||||
'J8': 'large office',
|
||||
'J9': 'large office',
|
||||
'K1': 'strip mall',
|
||||
'K2': 'strip mall',
|
||||
'K3': 'strip mall',
|
||||
'K4': 'residential',
|
||||
'K5': 'restaurant',
|
||||
'K6': 'commercial',
|
||||
'K7': 'commercial',
|
||||
'K8': 'commercial',
|
||||
'K9': 'commercial',
|
||||
'L1': 'residential',
|
||||
'L2': 'residential',
|
||||
'L3': 'residential',
|
||||
'L8': 'residential',
|
||||
'L9': 'residential',
|
||||
'M1': 'large office',
|
||||
'M2': 'large office',
|
||||
'M3': 'large office',
|
||||
'M4': 'large office',
|
||||
'M9': 'large office',
|
||||
'N1': 'residential',
|
||||
'N2': 'residential',
|
||||
'N3': 'residential',
|
||||
'N4': 'residential',
|
||||
'N9': 'residential',
|
||||
'O1': 'office',
|
||||
'O2': 'office',
|
||||
'O3': 'office',
|
||||
'O4': 'office',
|
||||
'O5': 'office',
|
||||
'O6': 'office',
|
||||
'O7': 'office',
|
||||
'O8': 'office',
|
||||
'O9': 'office',
|
||||
'P1': 'large office',
|
||||
'P2': 'hotel',
|
||||
'P3': 'office',
|
||||
'P4': 'office',
|
||||
'P5': 'office',
|
||||
'P6': 'office',
|
||||
'P7': 'large office',
|
||||
'P8': 'large office',
|
||||
'P9': 'office',
|
||||
'Q0': 'office',
|
||||
'Q1': 'office',
|
||||
'Q2': 'office',
|
||||
'Q3': 'office',
|
||||
'Q4': 'office',
|
||||
'Q5': 'office',
|
||||
'Q6': 'office',
|
||||
'Q7': 'office',
|
||||
'Q8': 'office',
|
||||
'Q9': 'office',
|
||||
'R0': 'residential',
|
||||
'R1': 'residential',
|
||||
'R2': 'residential',
|
||||
'R3': 'residential',
|
||||
'R4': 'residential',
|
||||
'R5': 'residential',
|
||||
'R6': 'residential',
|
||||
'R7': 'residential',
|
||||
'R8': 'residential',
|
||||
'R9': 'residential',
|
||||
'RA': 'residential',
|
||||
'RB': 'residential',
|
||||
'RC': 'residential',
|
||||
'RD': 'residential',
|
||||
'RG': 'residential',
|
||||
'RH': 'residential',
|
||||
'RI': 'residential',
|
||||
'RK': 'residential',
|
||||
'RM': 'residential',
|
||||
'RR': 'residential',
|
||||
'RS': 'residential',
|
||||
'RW': 'residential',
|
||||
'RX': 'residential',
|
||||
'RZ': 'residential',
|
||||
'S0': 'residential',
|
||||
'S1': 'residential',
|
||||
'S2': 'residential',
|
||||
'S3': 'residential',
|
||||
'S4': 'residential',
|
||||
'S5': 'residential',
|
||||
'S9': 'residential',
|
||||
'T1': 'na',
|
||||
'T2': 'na',
|
||||
'T9': 'na',
|
||||
'U0': 'warehouse',
|
||||
'U1': 'warehouse',
|
||||
'U2': 'warehouse',
|
||||
'U3': 'warehouse',
|
||||
'U4': 'warehouse',
|
||||
'U5': 'warehouse',
|
||||
'U6': 'warehouse',
|
||||
'U7': 'warehouse',
|
||||
'U8': 'warehouse',
|
||||
'U9': 'warehouse',
|
||||
'V0': 'na',
|
||||
'V1': 'na',
|
||||
'V2': 'na',
|
||||
'V3': 'na',
|
||||
'V4': 'na',
|
||||
'V5': 'na',
|
||||
'V6': 'na',
|
||||
'V7': 'na',
|
||||
'V8': 'na',
|
||||
'V9': 'na',
|
||||
'W1': 'primary school',
|
||||
'W2': 'primary school',
|
||||
'W3': 'secondary school',
|
||||
'W4': 'secondary school',
|
||||
'W5': 'secondary school',
|
||||
'W6': 'secondary school',
|
||||
'W7': 'secondary school',
|
||||
'W8': 'primary school',
|
||||
'W9': 'secondary school',
|
||||
'Y1': 'large office',
|
||||
'Y2': 'large office',
|
||||
'Y3': 'large office',
|
||||
'Y4': 'large office',
|
||||
'Y5': 'large office',
|
||||
'Y6': 'large office',
|
||||
'Y7': 'large office',
|
||||
'Y8': 'large office',
|
||||
'Y9': 'large office',
|
||||
'Z0': 'na',
|
||||
'Z1': 'large office',
|
||||
'Z2': 'na',
|
||||
'Z3': 'na',
|
||||
'Z4': 'na',
|
||||
'Z5': 'na',
|
||||
'Z6': 'na',
|
||||
'Z7': 'na',
|
||||
'Z8': 'na',
|
||||
'Z9': 'na'
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def function_to_usage(building_function):
|
||||
return UsFunctionToUsage.building_usage[building_function]
|
||||
|
||||
@staticmethod
|
||||
def pluto_to_function(pluto):
|
||||
return UsFunctionToUsage.building_function[pluto]
|
78
usage/usage_feeders/us_base_usage_parameters.py
Normal file
78
usage/usage_feeders/us_base_usage_parameters.py
Normal file
|
@ -0,0 +1,78 @@
|
|||
import xmltodict
|
||||
from pathlib import Path
|
||||
from city_model_structure.usage_zone import UsageZone
|
||||
from city_model_structure.internal_gains import InternalGains
|
||||
|
||||
|
||||
class UsBaseUsageParameters:
|
||||
def __init__(self, city, function_to_usage):
|
||||
self._city = city
|
||||
# ToDo: this is using the german library as a temporary approach, need to use/define a library for US
|
||||
path = str(Path.cwd() / 'data/usage/de_library.xml')
|
||||
with open(path) as xml:
|
||||
self._library = xmltodict.parse(xml.read(), force_list='zoneUsageVariant')
|
||||
for city_object in self._city.city_objects:
|
||||
#ToDo: Right now is just one usage zone but will be multiple in the future
|
||||
usage_zone = UsageZone()
|
||||
usage_zone.usage = function_to_usage(city_object.function)
|
||||
for zone_usage_type in self._library['buildingUsageLibrary']['zoneUsageType']:
|
||||
if zone_usage_type['id'] != usage_zone.usage:
|
||||
if 'zoneUsageVariant' in zone_usage_type:
|
||||
for usage_zone_variant in zone_usage_type['zoneUsageVariant']:
|
||||
if usage_zone_variant['id'] == usage_zone.usage:
|
||||
# pre-initialize the usage zone with the main type
|
||||
usage_zone = UsBaseUsageParameters._parse_zone_usage_type(zone_usage_type, usage_zone)
|
||||
usage_zone = UsBaseUsageParameters._parse_zone_usage_variant(usage_zone_variant, usage_zone)
|
||||
city_object.usage_zone = [usage_zone]
|
||||
break
|
||||
continue
|
||||
else:
|
||||
city_object.usage_zone = [UsBaseUsageParameters._parse_zone_usage_type(zone_usage_type, usage_zone)]
|
||||
break
|
||||
if city_object.usage_zone is None:
|
||||
print(city_object.function)
|
||||
raise Exception('Usage not found for building function')
|
||||
|
||||
|
||||
@staticmethod
|
||||
def _parse_zone_usage_type(zone_usage_type, usage_zone):
|
||||
usage_zone.hours_day = zone_usage_type['occupancy']['usageHoursPerDay']
|
||||
usage_zone.days_year = zone_usage_type['occupancy']['usageDaysPerYear']
|
||||
usage_zone.cooling_setpoint = zone_usage_type['endUses']['space_cooling']['coolingSetPointTemperature']
|
||||
usage_zone.heating_setpoint = zone_usage_type['endUses']['space_heating']['heatingSetPointTemperature']
|
||||
usage_zone.heating_setback = zone_usage_type['endUses']['space_heating']['heatingSetBackTemperature']
|
||||
if 'ventilation' in zone_usage_type['endUses'] and zone_usage_type['endUses']['ventilation'] is not None:
|
||||
usage_zone.mechanical_air_change = zone_usage_type['endUses']['ventilation']['mechanicalAirChangeRate']
|
||||
int_gains = InternalGains()
|
||||
int_gains.latent_fraction = zone_usage_type['occupancy']['internGains']['latentFraction']
|
||||
int_gains.convective_fraction = zone_usage_type['occupancy']['internGains']['convectiveFraction']
|
||||
int_gains.average_internal_gain_w_m2 = zone_usage_type['occupancy']['internGains']['averageInternGainPerSqm']
|
||||
int_gains.radiative_fraction = zone_usage_type['occupancy']['internGains']['radiantFraction']
|
||||
usage_zone.internal_gains = [int_gains]
|
||||
return usage_zone
|
||||
|
||||
@staticmethod
|
||||
def _parse_zone_usage_variant(usage_zone_variant, usage_zone):
|
||||
# for the variants all is optional because it mimics the inheritance concept from OOP
|
||||
if 'usageHoursPerDay' in usage_zone_variant['occupancy']:
|
||||
usage_zone.hours_day = usage_zone_variant['occupancy']['usageHoursPerDay']
|
||||
if 'usageDaysPerYear' in usage_zone_variant['occupancy']:
|
||||
usage_zone.days_year = usage_zone_variant['occupancy']['usageDaysPerYear']
|
||||
if 'coolingSetPointTemperature' in usage_zone_variant['endUses']['space_cooling']:
|
||||
usage_zone.cooling_setpoint = usage_zone_variant['endUses']['space_cooling']['coolingSetPointTemperature']
|
||||
if 'heatingSetPointTemperature' in usage_zone_variant['endUses']['space_heating']:
|
||||
usage_zone.heating_setpoint = usage_zone_variant['endUses']['space_heating']['heatingSetPointTemperature']
|
||||
if 'heatingSetBackTemperature' in usage_zone_variant['endUses']['space_heating']:
|
||||
usage_zone.heating_setback = usage_zone_variant['endUses']['space_heating']['heatingSetBackTemperature']
|
||||
if 'ventilation' in usage_zone_variant['endUses'] and usage_zone_variant['endUses']['ventilation'] is not None:
|
||||
usage_zone.mechanical_air_change = usage_zone_variant['endUses']['ventilation']['mechanicalAirChangeRate']
|
||||
if 'latentFraction' in usage_zone_variant['occupancy']['internGains']:
|
||||
usage_zone.int_gains[0].latent_fraction = usage_zone_variant['occupancy']['internGains']['latentFraction']
|
||||
if 'convectiveFraction' in usage_zone_variant['occupancy']['internGains']:
|
||||
usage_zone.int_gains[0].convective_fraction = usage_zone_variant['occupancy']['internGains']['convectiveFraction']
|
||||
if 'averageInternGainPerSqm' in usage_zone_variant['occupancy']['internGains']:
|
||||
usage_zone.int_gains[0].average_internal_gain_w_m2 = \
|
||||
usage_zone_variant['occupancy']['internGains']['averageInternGainPerSqm']
|
||||
if 'radiantFraction' in usage_zone_variant['occupancy']['internGains']:
|
||||
usage_zone.int_gains[0].radiative_fraction = usage_zone_variant['occupancy']['internGains']['radiantFraction']
|
||||
return usage_zone
|
7
usage/usage_feeders/us_new_york_city_usage_parameters.py
Normal file
7
usage/usage_feeders/us_new_york_city_usage_parameters.py
Normal file
|
@ -0,0 +1,7 @@
|
|||
from usage.usage_feeders.us_base_usage_parameters import UsBaseUsageParameters
|
||||
from usage.usage_feeders.helpers.us_function_to_usage import UsFunctionToUsage
|
||||
|
||||
|
||||
class UsNewYorkCityUsageParameters(UsBaseUsageParameters):
|
||||
def __init__(self, city):
|
||||
super().__init__(city, UsFunctionToUsage.pluto_to_function)
|
7
usage/usage_feeders/us_usage_parameters.py
Normal file
7
usage/usage_feeders/us_usage_parameters.py
Normal file
|
@ -0,0 +1,7 @@
|
|||
from usage.usage_feeders.us_base_usage_parameters import UsBaseUsageParameters
|
||||
from usage.usage_feeders.helpers.us_function_to_usage import UsFunctionToUsage
|
||||
|
||||
|
||||
class UsUsageParameters(UsBaseUsageParameters):
|
||||
def __init__(self, city):
|
||||
super().__init__(city, UsFunctionToUsage.function_to_usage)
|
10
usage/usagelibrary.py
Normal file
10
usage/usagelibrary.py
Normal file
|
@ -0,0 +1,10 @@
|
|||
class UsageLibrary:
|
||||
def __init__(self):
|
||||
self.standard = 1
|
||||
self.internal_gains = [4.2]
|
||||
self.heating_setpoint = [20.0]
|
||||
self.heating_setback = [16.0]
|
||||
self.cooling_setpoint = [25.0]
|
||||
self.hours_day = [17]
|
||||
self.days_year = [365]
|
||||
self.min_air_change = [0.34]
|
Loading…
Reference in New Issue
Block a user