Import the shared code files into the new repository

This commit is contained in:
Guille Gutierrez 2020-05-18 13:25:08 -04:00
parent 4ecefaf2d0
commit 0fe85d5956
27 changed files with 2042 additions and 0 deletions

View 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

View 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

View 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

View 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

View 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

View 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)

View 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

View 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

View 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

View 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

View 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

View 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

View 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)

View 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

View 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)()

View 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]

View 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]

View 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')

View File

@ -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)

View 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
View 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)()

View 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)

View 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]

View 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

View 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)

View 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
View 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]