Refactor and code quality improvements
This commit is contained in:
parent
82b72e78c7
commit
891b660824
0
hub/catalog_factories/__init__.py
Normal file
0
hub/catalog_factories/__init__.py
Normal file
0
hub/catalog_factories/construction/__init__.py
Normal file
0
hub/catalog_factories/construction/__init__.py
Normal file
0
hub/catalog_factories/cost/__init__.py
Normal file
0
hub/catalog_factories/cost/__init__.py
Normal file
0
hub/catalog_factories/data_models/__init__.py
Normal file
0
hub/catalog_factories/data_models/__init__.py
Normal file
0
hub/catalog_factories/data_models/cost/__init__.py
Normal file
0
hub/catalog_factories/data_models/cost/__init__.py
Normal file
0
hub/catalog_factories/energy_systems/__init__.py
Normal file
0
hub/catalog_factories/energy_systems/__init__.py
Normal file
0
hub/catalog_factories/greenery/__init__.py
Normal file
0
hub/catalog_factories/greenery/__init__.py
Normal file
|
@ -4,12 +4,12 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||
"""
|
||||
import logging
|
||||
|
||||
from pathlib import Path
|
||||
from typing import TypeVar
|
||||
|
||||
from hub.catalog_factories.greenery.greenery_catalog import GreeneryCatalog
|
||||
from hub.helpers.utils import validate_import_export_type
|
||||
|
||||
Catalog = TypeVar('Catalog')
|
||||
|
||||
|
||||
|
@ -19,9 +19,8 @@ class GreeneryCatalogFactory:
|
|||
"""
|
||||
def __init__(self, handler, base_path=None):
|
||||
if base_path is None:
|
||||
base_path = Path(Path(__file__).parent.parent / 'data/greenery')
|
||||
base_path = (Path(__file__).parent.parent / 'data/greenery').resolve()
|
||||
self._handler = '_' + handler.lower()
|
||||
class_funcs = validate_import_export_type(GreeneryCatalogFactory, handler)
|
||||
self._path = base_path
|
||||
|
||||
@property
|
||||
|
|
0
hub/catalog_factories/usage/__init__.py
Normal file
0
hub/catalog_factories/usage/__init__.py
Normal file
|
@ -148,13 +148,13 @@ class ComnetCatalog(Catalog):
|
|||
if day == cte.SATURDAY:
|
||||
start = start + 1
|
||||
end = end + 1
|
||||
elif day == cte.SUNDAY or day == cte.HOLIDAY:
|
||||
elif day in (cte.SUNDAY, cte.HOLIDAY):
|
||||
start = start + 2
|
||||
end = end + 2
|
||||
_schedule_values[day] = _extracted_data.iloc[start:end, 3:27].to_numpy().tolist()[0]
|
||||
_schedule = []
|
||||
for day in _schedule_values:
|
||||
if schedule_name == 'ClgSetPt' or schedule_name == 'HtgSetPt' or schedule_name == 'WtrHtrSetPt':
|
||||
if schedule_name in ('ClgSetPt', 'HtgSetPt', 'WtrHtrSetPt'):
|
||||
# to celsius
|
||||
if 'n.a.' in _schedule_values[day]:
|
||||
_schedule_values[day] = None
|
||||
|
|
|
@ -4,10 +4,10 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
import sys
|
||||
import hub.helpers.constants as cte
|
||||
from typing import Dict
|
||||
|
||||
import hub.helpers.constants as cte
|
||||
|
||||
|
||||
class UsageHelper:
|
||||
"""
|
||||
|
@ -92,41 +92,49 @@ class UsageHelper:
|
|||
|
||||
@property
|
||||
def nrcan_day_type_to_hub_days(self):
|
||||
"""
|
||||
Get a dictionary to convert nrcan day types to hub day types
|
||||
"""
|
||||
return self._nrcan_day_type_to_hub_days
|
||||
|
||||
@property
|
||||
def nrcan_schedule_type_to_hub_schedule_type(self):
|
||||
"""
|
||||
Get a dictionary to convert nrcan schedule types to hub schedule types
|
||||
"""
|
||||
return self._nrcan_schedule_type_to_hub_schedule_type
|
||||
|
||||
@property
|
||||
def nrcan_data_type_to_hub_data_type(self):
|
||||
"""
|
||||
Get a dictionary to convert nrcan data types to hub data types
|
||||
"""
|
||||
return self._nrcan_data_type_to_hub_data_type
|
||||
|
||||
@property
|
||||
def nrcan_time_to_hub_time(self):
|
||||
"""
|
||||
Get a dictionary to convert nrcan time to hub time
|
||||
"""
|
||||
return self._nrcan_time_to_hub_time
|
||||
|
||||
@property
|
||||
def comnet_data_type_to_hub_data_type(self):
|
||||
def comnet_data_type_to_hub_data_type(self) -> Dict:
|
||||
"""
|
||||
Get a dictionary to convert comnet data types to hub data types
|
||||
"""
|
||||
return self._comnet_data_type_to_hub_data_type
|
||||
|
||||
@property
|
||||
def comnet_schedules_key_to_comnet_schedules(self) -> Dict:
|
||||
"""
|
||||
Get a dictionary to convert hub schedules to comnet schedules
|
||||
"""
|
||||
return self._comnet_schedules_key_to_comnet_schedules
|
||||
|
||||
@property
|
||||
def comnet_days(self):
|
||||
def comnet_days(self) -> [str]:
|
||||
"""
|
||||
Get the list of days used in comnet
|
||||
"""
|
||||
return self._comnet_days
|
||||
|
||||
@staticmethod
|
||||
def schedules_key(usage):
|
||||
"""
|
||||
Get Comnet schedules key from the list found in the Comnet usage file
|
||||
:param usage: str
|
||||
:return: str
|
||||
"""
|
||||
try:
|
||||
return UsageHelper._comnet_schedules_key_to_comnet_schedules[usage]
|
||||
except KeyError:
|
||||
sys.stderr.write('Error: Comnet keyword not found. An update of the Comnet files might have been '
|
||||
'done changing the keywords.\n')
|
||||
|
|
0
hub/city_model_structure/__init__.py
Normal file
0
hub/city_model_structure/__init__.py
Normal file
0
hub/city_model_structure/attributes/__init__.py
Normal file
0
hub/city_model_structure/attributes/__init__.py
Normal file
|
@ -45,14 +45,13 @@ class Plane:
|
|||
:return: (A, B, C, D)
|
||||
"""
|
||||
if self._equation is None:
|
||||
|
||||
a = self.normal[0]
|
||||
b = self.normal[1]
|
||||
c = self.normal[2]
|
||||
d = ((-1 * self.origin.coordinates[0]) * self.normal[0])
|
||||
d += ((-1 * self.origin.coordinates[1]) * self.normal[1])
|
||||
d += ((-1 * self.origin.coordinates[2]) * self.normal[2])
|
||||
self._equation = (a, b, c, d)
|
||||
d = -1 * self.origin.coordinates[0] * self.normal[0]
|
||||
d += -1 * self.origin.coordinates[1] * self.normal[1]
|
||||
d += -1 * self.origin.coordinates[2] * self.normal[2]
|
||||
self._equation = a, b, c, d
|
||||
return self._equation
|
||||
|
||||
def distance_to_point(self, point):
|
||||
|
|
|
@ -31,7 +31,7 @@ class Point:
|
|||
:return: float
|
||||
"""
|
||||
power = 0
|
||||
for dimension in range(0, len(self.coordinates)):
|
||||
for dimension in enumerate(self.coordinates):
|
||||
power += math.pow(other_point.coordinates[dimension]-self.coordinates[dimension], 2)
|
||||
distance = math.sqrt(power)
|
||||
return distance
|
||||
|
|
|
@ -6,20 +6,21 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
|||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import math
|
||||
import sys
|
||||
from typing import List
|
||||
|
||||
import numpy as np
|
||||
from trimesh import Trimesh
|
||||
import trimesh.intersections
|
||||
import trimesh.creation
|
||||
import trimesh.geometry
|
||||
import trimesh.intersections
|
||||
from shapely.geometry.polygon import Polygon as shapley_polygon
|
||||
from trimesh import Trimesh
|
||||
|
||||
from hub.city_model_structure.attributes.plane import Plane
|
||||
from hub.city_model_structure.attributes.point import Point
|
||||
import hub.helpers.constants as cte
|
||||
|
||||
|
||||
class Polygon:
|
||||
|
@ -69,44 +70,6 @@ class Polygon:
|
|||
"""
|
||||
return self._coordinates
|
||||
|
||||
def contains_point(self, point):
|
||||
"""
|
||||
Determines if the given point is contained by the current polygon
|
||||
:return: boolean
|
||||
"""
|
||||
# fixme: This method doesn't seems to work.
|
||||
n = len(self.vertices)
|
||||
angle_sum = 0
|
||||
for i in range(0, n):
|
||||
vector_0 = self.vertices[i]
|
||||
vector_1 = self.vertices[(i+1) % n]
|
||||
# set to origin
|
||||
vector_0[0] = vector_0[0] - point.coordinates[0]
|
||||
vector_0[1] = vector_0[1] - point.coordinates[1]
|
||||
vector_0[2] = vector_0[2] - point.coordinates[2]
|
||||
vector_1[0] = vector_1[0] - point.coordinates[0]
|
||||
vector_1[1] = vector_1[1] - point.coordinates[1]
|
||||
vector_1[2] = vector_1[2] - point.coordinates[2]
|
||||
module = np.linalg.norm(vector_0) * np.linalg.norm(vector_1)
|
||||
|
||||
scalar_product = np.dot(vector_0, vector_1)
|
||||
angle = np.pi/2
|
||||
if module != 0:
|
||||
angle = abs(np.arcsin(scalar_product / module))
|
||||
angle_sum += angle
|
||||
return abs(angle_sum - math.pi*2) < cte.EPSILON
|
||||
|
||||
def contains_polygon(self, polygon):
|
||||
"""
|
||||
Determines if the given polygon is contained by the current polygon
|
||||
:return: boolean
|
||||
"""
|
||||
|
||||
for point in polygon.points:
|
||||
if not self.contains_point(point):
|
||||
return False
|
||||
return True
|
||||
|
||||
@property
|
||||
def points_list(self) -> np.ndarray:
|
||||
"""
|
||||
|
@ -142,12 +105,12 @@ class Polygon:
|
|||
if self._area is None:
|
||||
self._area = 0
|
||||
for triangle in self.triangles:
|
||||
ab = np.zeros(3)
|
||||
ac = np.zeros(3)
|
||||
a_b = np.zeros(3)
|
||||
a_c = np.zeros(3)
|
||||
for i in range(0, 3):
|
||||
ab[i] = triangle.coordinates[1][i] - triangle.coordinates[0][i]
|
||||
ac[i] = triangle.coordinates[2][i] - triangle.coordinates[0][i]
|
||||
self._area += np.linalg.norm(np.cross(ab, ac)) / 2
|
||||
a_b[i] = triangle.coordinates[1][i] - triangle.coordinates[0][i]
|
||||
a_c[i] = triangle.coordinates[2][i] - triangle.coordinates[0][i]
|
||||
self._area += np.linalg.norm(np.cross(a_b, a_c)) / 2
|
||||
return self._area
|
||||
|
||||
@area.setter
|
||||
|
@ -217,7 +180,11 @@ class Polygon:
|
|||
return -alpha
|
||||
|
||||
@staticmethod
|
||||
def triangle_mesh(vertices, normal):
|
||||
def triangle_mesh(vertices, normal) -> Trimesh:
|
||||
"""
|
||||
Get the triangulated mesh for the polygon
|
||||
:return: Trimesh
|
||||
"""
|
||||
min_x = 1e16
|
||||
min_y = 1e16
|
||||
min_z = 1e16
|
||||
|
@ -246,8 +213,7 @@ class Polygon:
|
|||
polygon = shapley_polygon(coordinates)
|
||||
|
||||
try:
|
||||
|
||||
vertices_2d, faces = trimesh.creation.triangulate_polygon(polygon, engine='triangle')
|
||||
_, faces = trimesh.creation.triangulate_polygon(polygon, engine='triangle')
|
||||
|
||||
mesh = Trimesh(vertices=vertices, faces=faces)
|
||||
|
||||
|
@ -267,13 +233,17 @@ class Polygon:
|
|||
return mesh
|
||||
|
||||
except ValueError:
|
||||
logging.error(f'Not able to triangulate polygon\n')
|
||||
logging.error('Not able to triangulate polygon\n')
|
||||
_vertices = [[0, 0, 0], [0, 0, 1], [0, 1, 0]]
|
||||
_faces = [[0, 1, 2]]
|
||||
return Trimesh(vertices=_vertices, faces=_faces)
|
||||
|
||||
@property
|
||||
def triangles(self) -> List[Polygon]:
|
||||
"""
|
||||
Triangulate the polygon and return a list of triangular polygons
|
||||
:return: [Polygon]
|
||||
"""
|
||||
if self._triangles is None:
|
||||
self._triangles = []
|
||||
_mesh = self.triangle_mesh(self.coordinates, self.normal)
|
||||
|
@ -336,7 +306,7 @@ class Polygon:
|
|||
|
||||
def _reshape(self, triangles) -> Polygon:
|
||||
edges_list = []
|
||||
for i in range(0, len(triangles)):
|
||||
for i in enumerate(triangles):
|
||||
for edge in triangles[i].edges:
|
||||
if not self._edge_in_edges_list(edge, edges_list):
|
||||
edges_list.append(edge)
|
||||
|
@ -421,7 +391,8 @@ class Polygon:
|
|||
if len(points) != 3:
|
||||
sub_polygons = polygon.triangles
|
||||
# todo: I modified this! To be checked @Guille
|
||||
if len(sub_polygons) >= 1:
|
||||
if len(sub_polygons) < 1:
|
||||
continue
|
||||
for sub_polygon in sub_polygons:
|
||||
face = []
|
||||
points = sub_polygon.coordinates
|
||||
|
@ -440,7 +411,7 @@ class Polygon:
|
|||
:return: int
|
||||
"""
|
||||
vertices = self.vertices
|
||||
for i in range(len(vertices)):
|
||||
for i in enumerate(vertices):
|
||||
# ensure not duplicated vertex
|
||||
power = 0
|
||||
vertex2 = vertices[i]
|
||||
|
|
|
@ -41,10 +41,10 @@ class Polyhedron:
|
|||
:return: int
|
||||
"""
|
||||
vertices = self.vertices
|
||||
for i in range(len(vertices)):
|
||||
for i, vertex in enumerate(vertices):
|
||||
# ensure not duplicated vertex
|
||||
power = 0
|
||||
vertex2 = vertices[i]
|
||||
vertex2 = vertex
|
||||
for dimension in range(0, 3):
|
||||
power += math.pow(vertex2[dimension] - point[dimension], 2)
|
||||
distance = math.sqrt(power)
|
||||
|
@ -92,7 +92,8 @@ class Polyhedron:
|
|||
points = polygon.coordinates
|
||||
if len(points) != 3:
|
||||
sub_polygons = polygon.triangles
|
||||
if len(sub_polygons) >= 1:
|
||||
if len(sub_polygons) < 1:
|
||||
continue
|
||||
for sub_polygon in sub_polygons:
|
||||
face = []
|
||||
points = sub_polygon.coordinates
|
||||
|
|
|
@ -45,17 +45,17 @@ class Building(CityObject):
|
|||
self._shell = None
|
||||
self._aliases = None
|
||||
self._type = 'building'
|
||||
self._cold_water_temperature = dict()
|
||||
self._heating = dict()
|
||||
self._cooling = dict()
|
||||
self._lighting_electrical_demand = dict()
|
||||
self._appliances_electrical_demand = dict()
|
||||
self._domestic_hot_water_heat_demand = dict()
|
||||
self._heating_consumption = dict()
|
||||
self._cooling_consumption = dict()
|
||||
self._domestic_hot_water_consumption = dict()
|
||||
self._distribution_systems_electrical_consumption = dict()
|
||||
self._onsite_electrical_production = dict()
|
||||
self._cold_water_temperature = {}
|
||||
self._heating = {}
|
||||
self._cooling = {}
|
||||
self._lighting_electrical_demand = {}
|
||||
self._appliances_electrical_demand = {}
|
||||
self._domestic_hot_water_heat_demand = {}
|
||||
self._heating_consumption = {}
|
||||
self._cooling_consumption = {}
|
||||
self._domestic_hot_water_consumption = {}
|
||||
self._distribution_systems_electrical_consumption = {}
|
||||
self._onsite_electrical_production = {}
|
||||
self._eave_height = None
|
||||
self._energy_systems = None
|
||||
self._systems_archetype_name = None
|
||||
|
@ -86,7 +86,8 @@ class Building(CityObject):
|
|||
elif surface.type == cte.INTERIOR_SLAB:
|
||||
self._interior_slabs.append(surface)
|
||||
else:
|
||||
logging.error(f'Building {self.name} [{self.aliases}] has an unexpected surface type {surface.type}.\n')
|
||||
error = f'Building {self.name} [{self.aliases}] has an unexpected surface type {surface.type}.\n'
|
||||
logging.error(error)
|
||||
|
||||
@property
|
||||
def shell(self) -> Polyhedron:
|
||||
|
@ -612,11 +613,11 @@ class Building(CityObject):
|
|||
if len(_working_hours) == 0:
|
||||
_working_hours = _working_hours_per_thermal_zone
|
||||
else:
|
||||
for key in _working_hours.keys():
|
||||
for key, item in _working_hours.items():
|
||||
saved_values = _working_hours_per_thermal_zone[key]
|
||||
for i, value in enumerate(_working_hours[key]):
|
||||
for i, value in enumerate(item):
|
||||
if saved_values[i] == 1:
|
||||
_working_hours[key][i] = 1
|
||||
value = 1
|
||||
_total_hours = 0
|
||||
for key in _working_hours:
|
||||
_total_hours += _working_hours[key] * cte.DAYS_A_YEAR[key]
|
||||
|
@ -628,7 +629,8 @@ class Building(CityObject):
|
|||
Get total electricity consumption for distribution and emission systems in Wh
|
||||
return: dict
|
||||
"""
|
||||
if len(self._distribution_systems_electrical_consumption) == 0:
|
||||
if len(self._distribution_systems_electrical_consumption) != 0:
|
||||
return self._distribution_systems_electrical_consumption
|
||||
_peak_load = self.heating_peak_load[cte.YEAR]['heating peak loads'][0]
|
||||
_peak_load_type = cte.HEATING
|
||||
if _peak_load < self.cooling_peak_load[cte.YEAR]['cooling peak loads'][0]:
|
||||
|
@ -648,7 +650,7 @@ class Building(CityObject):
|
|||
for heating_demand_key in self.heating:
|
||||
_consumption = [0]*len(self.heating)
|
||||
_demand = self.heating[heating_demand_key][cte.INSEL_MEB]
|
||||
for i in range(0, len(_consumption)):
|
||||
for i in enumerate(_consumption):
|
||||
_consumption[i] += (parasitic_energy_consumption + consumption_variable_flow) * _demand[i]
|
||||
self._distribution_systems_electrical_consumption[heating_demand_key] = _consumption
|
||||
if demand_type.lower() == cte.COOLING:
|
||||
|
@ -657,12 +659,12 @@ class Building(CityObject):
|
|||
for demand_key in self.cooling:
|
||||
_consumption = self._distribution_systems_electrical_consumption[demand_key]
|
||||
_demand = self.cooling[demand_key][cte.INSEL_MEB]
|
||||
for i in range(0, len(_consumption)):
|
||||
for i in enumerate(_consumption):
|
||||
_consumption[i] += (parasitic_energy_consumption + consumption_variable_flow) * _demand[i]
|
||||
self._distribution_systems_electrical_consumption[demand_key] = _consumption
|
||||
|
||||
for key in self._distribution_systems_electrical_consumption:
|
||||
for i in range(0, len(self._distribution_systems_electrical_consumption[key])):
|
||||
for key, item in self._distribution_systems_electrical_consumption.items():
|
||||
for i in range(0, len(item)):
|
||||
self._distribution_systems_electrical_consumption[key][i] += _peak_load * _consumption_fix_flow \
|
||||
* self._calculate_working_hours()
|
||||
return self._distribution_systems_electrical_consumption
|
||||
|
@ -673,7 +675,7 @@ class Building(CityObject):
|
|||
for energy_system in self.energy_systems:
|
||||
for demand_type in energy_system.demand_types:
|
||||
if demand_type.lower() == consumption_type.lower():
|
||||
if consumption_type == cte.HEATING or consumption_type == cte.DOMESTIC_HOT_WATER:
|
||||
if consumption_type in (cte.HEATING, cte.DOMESTIC_HOT_WATER):
|
||||
coefficient_of_performance = energy_system.generation_system.generic_generation_system.heat_efficiency
|
||||
elif consumption_type == cte.COOLING:
|
||||
coefficient_of_performance = energy_system.generation_system.generic_generation_system.cooling_efficiency
|
||||
|
|
|
@ -10,8 +10,8 @@ from __future__ import annotations
|
|||
|
||||
import math
|
||||
import uuid
|
||||
import numpy as np
|
||||
from typing import List, Union
|
||||
import numpy as np
|
||||
from hub.city_model_structure.attributes.polygon import Polygon
|
||||
from hub.city_model_structure.attributes.plane import Plane
|
||||
from hub.city_model_structure.attributes.point import Point
|
||||
|
@ -34,7 +34,7 @@ class Surface:
|
|||
self._area = None
|
||||
self._lower_corner = None
|
||||
self._upper_corner = None
|
||||
self._global_irradiance = dict()
|
||||
self._global_irradiance = {}
|
||||
self._perimeter_polygon = perimeter_polygon
|
||||
self._holes_polygons = holes_polygons
|
||||
self._solid_polygon = solid_polygon
|
||||
|
|
|
@ -226,7 +226,7 @@ class ThermalBoundary:
|
|||
r_value += float(layer.thickness) / float(layer.material.conductivity)
|
||||
self._u_value = 1.0/r_value
|
||||
except TypeError:
|
||||
raise Exception('Constructions layers are not initialized') from TypeError
|
||||
raise TypeError('Constructions layers are not initialized') from TypeError
|
||||
return self._u_value
|
||||
|
||||
@u_value.setter
|
||||
|
|
|
@ -8,8 +8,9 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord
|
|||
|
||||
import uuid
|
||||
import copy
|
||||
import numpy
|
||||
from typing import List, Union, TypeVar
|
||||
import numpy
|
||||
|
||||
from hub.city_model_structure.building_demand.occupancy import Occupancy
|
||||
from hub.city_model_structure.building_demand.appliances import Appliances
|
||||
from hub.city_model_structure.building_demand.lighting import Lighting
|
||||
|
@ -59,7 +60,11 @@ class ThermalZone:
|
|||
|
||||
@property
|
||||
def usages(self):
|
||||
# example 70-office_30-residential
|
||||
"""
|
||||
Get the thermal zone usages including percentage with the format [percentage]-usage_[percentage]-usage...
|
||||
Eg: 70-office_30-residential
|
||||
:return: str
|
||||
"""
|
||||
if self._usage_from_parent:
|
||||
self._usages = copy.deepcopy(self._parent_internal_zone.usages)
|
||||
else:
|
||||
|
@ -324,19 +329,19 @@ class ThermalZone:
|
|||
_occupancy_reference = self.usages[0].occupancy
|
||||
if _occupancy_reference.occupancy_schedules is not None:
|
||||
_schedules = []
|
||||
for i_schedule in range(0, len(_occupancy_reference.occupancy_schedules)):
|
||||
for schedule_index, schedule_value in enumerate(_occupancy_reference.occupancy_schedules):
|
||||
schedule = Schedule()
|
||||
schedule.type = _occupancy_reference.occupancy_schedules[i_schedule].type
|
||||
schedule.day_types = _occupancy_reference.occupancy_schedules[i_schedule].day_types
|
||||
schedule.data_type = _occupancy_reference.occupancy_schedules[i_schedule].data_type
|
||||
schedule.time_step = _occupancy_reference.occupancy_schedules[i_schedule].time_step
|
||||
schedule.time_range = _occupancy_reference.occupancy_schedules[i_schedule].time_range
|
||||
schedule.type = schedule_value.type
|
||||
schedule.day_types = schedule_value.day_types
|
||||
schedule.data_type = schedule_value.data_type
|
||||
schedule.time_step = schedule_value.time_step
|
||||
schedule.time_range = schedule_value.time_range
|
||||
|
||||
new_values = []
|
||||
for i_value in range(0, len(_occupancy_reference.occupancy_schedules[i_schedule].values)):
|
||||
for i_value, _ in enumerate(schedule_value.values):
|
||||
_new_value = 0
|
||||
for usage in self.usages:
|
||||
_new_value += usage.percentage * usage.occupancy.occupancy_schedules[i_schedule].values[i_value]
|
||||
_new_value += usage.percentage * usage.occupancy.occupancy_schedules[schedule_index].values[i_value]
|
||||
new_values.append(_new_value)
|
||||
schedule.values = new_values
|
||||
_schedules.append(schedule)
|
||||
|
@ -385,19 +390,19 @@ class ThermalZone:
|
|||
_lighting_reference = self.usages[0].lighting
|
||||
if _lighting_reference.schedules is not None:
|
||||
_schedules = []
|
||||
for i_schedule in range(0, len(_lighting_reference.schedules)):
|
||||
for schedule_index, schedule_value in enumerate(_lighting_reference.schedules):
|
||||
schedule = Schedule()
|
||||
schedule.type = _lighting_reference.schedules[i_schedule].type
|
||||
schedule.day_types = _lighting_reference.schedules[i_schedule].day_types
|
||||
schedule.data_type = _lighting_reference.schedules[i_schedule].data_type
|
||||
schedule.time_step = _lighting_reference.schedules[i_schedule].time_step
|
||||
schedule.time_range = _lighting_reference.schedules[i_schedule].time_range
|
||||
schedule.type = schedule_value.type
|
||||
schedule.day_types = schedule_value.day_types
|
||||
schedule.data_type = schedule_value.data_type
|
||||
schedule.time_step = schedule_value.time_step
|
||||
schedule.time_range = schedule_value.time_range
|
||||
|
||||
new_values = []
|
||||
for i_value in range(0, len(_lighting_reference.schedules[i_schedule].values)):
|
||||
for i_value, _ in enumerate(schedule_value.values):
|
||||
_new_value = 0
|
||||
for usage in self.usages:
|
||||
_new_value += usage.percentage * usage.lighting.schedules[i_schedule].values[i_value]
|
||||
_new_value += usage.percentage * usage.lighting.schedules[schedule_index].values[i_value]
|
||||
new_values.append(_new_value)
|
||||
schedule.values = new_values
|
||||
_schedules.append(schedule)
|
||||
|
@ -446,19 +451,19 @@ class ThermalZone:
|
|||
_appliances_reference = self.usages[0].appliances
|
||||
if _appliances_reference.schedules is not None:
|
||||
_schedules = []
|
||||
for i_schedule in range(0, len(_appliances_reference.schedules)):
|
||||
for schedule_index, schedule_value in enumerate(_appliances_reference.schedules):
|
||||
schedule = Schedule()
|
||||
schedule.type = _appliances_reference.schedules[i_schedule].type
|
||||
schedule.day_types = _appliances_reference.schedules[i_schedule].day_types
|
||||
schedule.data_type = _appliances_reference.schedules[i_schedule].data_type
|
||||
schedule.time_step = _appliances_reference.schedules[i_schedule].time_step
|
||||
schedule.time_range = _appliances_reference.schedules[i_schedule].time_range
|
||||
schedule.type = schedule_value.type
|
||||
schedule.day_types = schedule_value.day_types
|
||||
schedule.data_type = schedule_value.data_type
|
||||
schedule.time_step = schedule_value.time_step
|
||||
schedule.time_range = schedule_value.time_range
|
||||
|
||||
new_values = []
|
||||
for i_value in range(0, len(_appliances_reference.schedules[i_schedule].values)):
|
||||
for i_value, _ in enumerate(schedule_value.values):
|
||||
_new_value = 0
|
||||
for usage in self.usages:
|
||||
_new_value += usage.percentage * usage.appliances.schedules[i_schedule].values[i_value]
|
||||
_new_value += usage.percentage * usage.appliances.schedules[schedule_index].values[i_value]
|
||||
new_values.append(_new_value)
|
||||
schedule.values = new_values
|
||||
_schedules.append(schedule)
|
||||
|
@ -510,12 +515,12 @@ class ThermalZone:
|
|||
_schedules_defined = False
|
||||
break
|
||||
for day, _schedule in enumerate(internal_gain.schedules):
|
||||
for v, value in enumerate(_schedule.values):
|
||||
values[v, day] += value * usage.percentage
|
||||
for v_index, value in enumerate(_schedule.values):
|
||||
values[v_index, day] += value * usage.percentage
|
||||
|
||||
if _schedules_defined:
|
||||
_schedules = []
|
||||
for day in range(0, len(_days)):
|
||||
for day, _ in enumerate(_days):
|
||||
_schedule = copy.deepcopy(_base_schedule)
|
||||
_schedule.day_types = [_days[day]]
|
||||
_schedule.values = values[:day]
|
||||
|
@ -543,7 +548,8 @@ class ThermalZone:
|
|||
if self.usages is None:
|
||||
return None
|
||||
|
||||
if self._thermal_control is None:
|
||||
if self._thermal_control is not None:
|
||||
return self._thermal_control
|
||||
self._thermal_control = ThermalControl()
|
||||
_mean_heating_set_point = 0
|
||||
_heating_set_back = 0
|
||||
|
@ -565,19 +571,19 @@ class ThermalZone:
|
|||
if _thermal_control_reference.cooling_set_point_schedules is not None:
|
||||
_types_reference.append([cte.COOLING_SET_POINT, _thermal_control_reference.cooling_set_point_schedules])
|
||||
|
||||
for i_type in range(0, len(_types_reference)):
|
||||
for i_type, _ in enumerate(_types_reference):
|
||||
_schedules = []
|
||||
_schedule_type = _types_reference[i_type][1]
|
||||
for i_schedule in range(0, len(_schedule_type)):
|
||||
for i_schedule, schedule_value in enumerate(_schedule_type):
|
||||
schedule = Schedule()
|
||||
schedule.type = _schedule_type[i_schedule].type
|
||||
schedule.day_types = _schedule_type[i_schedule].day_types
|
||||
schedule.data_type = _schedule_type[i_schedule].data_type
|
||||
schedule.time_step = _schedule_type[i_schedule].time_step
|
||||
schedule.time_range = _schedule_type[i_schedule].time_range
|
||||
schedule.type = schedule_value.type
|
||||
schedule.day_types = schedule_value.day_types
|
||||
schedule.data_type = schedule_value.data_type
|
||||
schedule.time_step = schedule_value.time_step
|
||||
schedule.time_range = schedule_value.time_range
|
||||
|
||||
new_values = []
|
||||
for i_value in range(0, len(_schedule_type[i_schedule].values)):
|
||||
for i_value, _ in enumerate(schedule_value.values):
|
||||
_new_value = 0
|
||||
for usage in self.usages:
|
||||
if _types_reference[i_type][0] == cte.HVAC_AVAILABILITY:
|
||||
|
@ -598,7 +604,6 @@ class ThermalZone:
|
|||
self._thermal_control.heating_set_point_schedules = _schedules
|
||||
elif i_type == 2:
|
||||
self._thermal_control.cooling_set_point_schedules = _schedules
|
||||
|
||||
return self._thermal_control
|
||||
|
||||
@property
|
||||
|
@ -622,19 +627,19 @@ class ThermalZone:
|
|||
_domestic_hot_water_reference = self.usages[0].domestic_hot_water
|
||||
if _domestic_hot_water_reference.schedules is not None:
|
||||
_schedules = []
|
||||
for i_schedule in range(0, len(_domestic_hot_water_reference.schedules)):
|
||||
for schedule_index, schedule_value in enumerate(_domestic_hot_water_reference.schedules):
|
||||
schedule = Schedule()
|
||||
schedule.type = _domestic_hot_water_reference.schedules[i_schedule].type
|
||||
schedule.day_types = _domestic_hot_water_reference.schedules[i_schedule].day_types
|
||||
schedule.data_type = _domestic_hot_water_reference.schedules[i_schedule].data_type
|
||||
schedule.time_step = _domestic_hot_water_reference.schedules[i_schedule].time_step
|
||||
schedule.time_range = _domestic_hot_water_reference.schedules[i_schedule].time_range
|
||||
schedule.type = schedule_value.type
|
||||
schedule.day_types = schedule_value.day_types
|
||||
schedule.data_type = schedule_value.data_type
|
||||
schedule.time_step = schedule_value.time_step
|
||||
schedule.time_range = schedule_value.time_range
|
||||
|
||||
new_values = []
|
||||
for i_value in range(0, len(_domestic_hot_water_reference.schedules[i_schedule].values)):
|
||||
for i_value, _ in enumerate(schedule_value.values):
|
||||
_new_value = 0
|
||||
for usage in self.usages:
|
||||
_new_value += usage.percentage * usage.domestic_hot_water.schedules[i_schedule].values[i_value]
|
||||
_new_value += usage.percentage * usage.domestic_hot_water.schedules[schedule_index].values[i_value]
|
||||
new_values.append(_new_value)
|
||||
schedule.values = new_values
|
||||
_schedules.append(schedule)
|
||||
|
|
|
@ -8,29 +8,27 @@ Code contributors: Peter Yefi peteryefi@gmail.com
|
|||
from __future__ import annotations
|
||||
|
||||
import bz2
|
||||
import logging
|
||||
import sys
|
||||
import pickle
|
||||
import math
|
||||
import copy
|
||||
import pyproj
|
||||
from typing import List, Union
|
||||
from pyproj import Transformer
|
||||
import logging
|
||||
import math
|
||||
import pickle
|
||||
from pathlib import Path
|
||||
from typing import List, Union
|
||||
|
||||
import pyproj
|
||||
from pandas import DataFrame
|
||||
from pyproj import Transformer
|
||||
|
||||
from hub.city_model_structure.building import Building
|
||||
from hub.city_model_structure.buildings_cluster import BuildingsCluster
|
||||
from hub.city_model_structure.city_object import CityObject
|
||||
from hub.city_model_structure.city_objects_cluster import CityObjectsCluster
|
||||
from hub.city_model_structure.buildings_cluster import BuildingsCluster
|
||||
|
||||
from hub.city_model_structure.energy_system import EnergySystem
|
||||
from hub.city_model_structure.iot.station import Station
|
||||
from hub.city_model_structure.level_of_detail import LevelOfDetail
|
||||
from hub.city_model_structure.parts_consisting_building import PartsConsistingBuilding
|
||||
from hub.helpers.geometry_helper import GeometryHelper
|
||||
from hub.helpers.location import Location
|
||||
import hub.helpers.constants as cte
|
||||
from hub.city_model_structure.energy_system import EnergySystem
|
||||
import pandas as pd
|
||||
|
||||
|
||||
class City:
|
||||
|
@ -70,11 +68,11 @@ class City:
|
|||
if self._location is None:
|
||||
gps = pyproj.CRS('EPSG:4326') # LatLon with WGS84 datum used by GPS units and Google Earth
|
||||
try:
|
||||
if self._srs_name in GeometryHelper.srs_transformations.keys():
|
||||
if self._srs_name in GeometryHelper.srs_transformations:
|
||||
self._srs_name = GeometryHelper.srs_transformations[self._srs_name]
|
||||
input_reference = pyproj.CRS(self.srs_name) # Projected coordinate system from input data
|
||||
except pyproj.exceptions.CRSError as err:
|
||||
logging.error('Invalid projection reference system, please check the input data. (e.g. in CityGML files: srs_name)')
|
||||
logging.error('Invalid projection reference system, please check the input data.')
|
||||
raise pyproj.exceptions.CRSError from err
|
||||
transformer = Transformer.from_crs(input_reference, gps)
|
||||
coordinates = transformer.transform(self.lower_corner[0], self.lower_corner[1])
|
||||
|
@ -90,7 +88,11 @@ class City:
|
|||
return self._get_location().country
|
||||
|
||||
@property
|
||||
def location(self):
|
||||
def location(self) -> Location:
|
||||
"""
|
||||
Get city location
|
||||
:return: Location
|
||||
"""
|
||||
return self._get_location().city
|
||||
|
||||
@property
|
||||
|
@ -203,8 +205,11 @@ class City:
|
|||
return None
|
||||
|
||||
def add_building_alias(self, building, alias):
|
||||
"""
|
||||
Add an alias to the building
|
||||
"""
|
||||
building_index = self._city_objects_dictionary[building.name]
|
||||
if alias in self._city_objects_alias_dictionary.keys():
|
||||
if alias in self._city_objects_alias_dictionary:
|
||||
self._city_objects_alias_dictionary[alias].append(building_index)
|
||||
else:
|
||||
self._city_objects_alias_dictionary[alias] = [building_index]
|
||||
|
@ -218,7 +223,6 @@ class City:
|
|||
if new_city_object.type == 'building':
|
||||
if self._buildings is None:
|
||||
self._buildings = []
|
||||
new_city_object._alias_dictionary = self._city_objects_alias_dictionary
|
||||
self._buildings.append(new_city_object)
|
||||
self._city_objects_dictionary[new_city_object.name] = len(self._buildings) - 1
|
||||
if new_city_object.aliases is not None:
|
||||
|
@ -242,17 +246,17 @@ class City:
|
|||
"""
|
||||
if city_object.type != 'building':
|
||||
raise NotImplementedError(city_object.type)
|
||||
if self._buildings is None or self._buildings == []:
|
||||
sys.stderr.write('Warning: impossible to remove city_object, the city is empty\n')
|
||||
if not self._buildings:
|
||||
logging.warning('impossible to remove city_object, the city is empty\n')
|
||||
else:
|
||||
if city_object in self._buildings:
|
||||
self._buildings.remove(city_object)
|
||||
# regenerate hash map
|
||||
self._city_objects_dictionary.clear()
|
||||
self._city_objects_alias_dictionary.clear()
|
||||
for i, city_object in enumerate(self._buildings):
|
||||
self._city_objects_dictionary[city_object.name] = i
|
||||
for alias in city_object.aliases:
|
||||
for i, _building in enumerate(self._buildings):
|
||||
self._city_objects_dictionary[_building.name] = i
|
||||
for alias in _building.aliases:
|
||||
if alias in self._city_objects_alias_dictionary:
|
||||
self._city_objects_alias_dictionary[alias].append(i)
|
||||
else:
|
||||
|
@ -300,8 +304,8 @@ class City:
|
|||
:param city_filename: destination city filename
|
||||
:return: None
|
||||
"""
|
||||
with bz2.BZ2File(city_filename, 'wb') as f:
|
||||
pickle.dump(self, f)
|
||||
with bz2.BZ2File(city_filename, 'wb') as file:
|
||||
pickle.dump(self, file)
|
||||
|
||||
def region(self, center, radius) -> City:
|
||||
"""
|
||||
|
@ -446,6 +450,10 @@ class City:
|
|||
return copy.deepcopy(self)
|
||||
|
||||
def merge(self, city) -> City:
|
||||
"""
|
||||
Return a merged city combining the current city and the given one
|
||||
:return: City
|
||||
"""
|
||||
raise NotImplementedError('This method needs to be reimplemented')
|
||||
|
||||
@property
|
||||
|
|
|
@ -37,11 +37,11 @@ class CityObject:
|
|||
self._max_z = ConfigurationHelper().min_coordinate
|
||||
self._centroid = None
|
||||
self._volume = None
|
||||
self._external_temperature = dict()
|
||||
self._ground_temperature = dict()
|
||||
self._global_horizontal = dict()
|
||||
self._diffuse = dict()
|
||||
self._beam = dict()
|
||||
self._external_temperature = {}
|
||||
self._ground_temperature = {}
|
||||
self._global_horizontal = {}
|
||||
self._diffuse = {}
|
||||
self._beam = {}
|
||||
self._sensors = []
|
||||
self._neighbours = None
|
||||
|
||||
|
|
0
hub/city_model_structure/energy_systems/__init__.py
Normal file
0
hub/city_model_structure/energy_systems/__init__.py
Normal file
|
@ -1,5 +1,5 @@
|
|||
"""
|
||||
Energy control system definition
|
||||
Energy control system module
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2023 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
"""
|
||||
Generic energy emission system definition
|
||||
Generic energy emission system module
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2023 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
|
|
|
@ -46,7 +46,7 @@ class HeatPump:
|
|||
|
||||
@hp_monthly_fossil_consumption.setter
|
||||
def hp_monthly_fossil_consumption(self, value):
|
||||
if type(value) is Series:
|
||||
if isinstance(value, Series):
|
||||
self._hp_monthly_fossil_consumption = value
|
||||
|
||||
@property
|
||||
|
@ -60,5 +60,5 @@ class HeatPump:
|
|||
|
||||
@hp_monthly_electricity_demand.setter
|
||||
def hp_monthly_electricity_demand(self, value):
|
||||
if type(value) == Series:
|
||||
if isinstance(value, Series):
|
||||
self._hp_monthly_electricity_demand = value
|
||||
|
|
|
@ -30,4 +30,3 @@ class HvacTerminalUnit:
|
|||
"""
|
||||
if value is not None:
|
||||
self._type = str(value)
|
||||
|
||||
|
|
0
hub/city_model_structure/greenery/__init__.py
Normal file
0
hub/city_model_structure/greenery/__init__.py
Normal file
|
@ -1,5 +1,5 @@
|
|||
"""
|
||||
Plant class
|
||||
Plant module
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
|
@ -10,6 +10,9 @@ from hub.city_model_structure.greenery.soil import Soil
|
|||
|
||||
|
||||
class Plant:
|
||||
"""
|
||||
Plant class
|
||||
"""
|
||||
def __init__(self, name, height, leaf_area_index, leaf_reflectivity, leaf_emissivity, minimal_stomatal_resistance,
|
||||
co2_sequestration, grows_on_soils):
|
||||
self._name = name
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
"""
|
||||
Soil class
|
||||
Soil module
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
|
@ -7,6 +7,9 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
|||
|
||||
|
||||
class Soil:
|
||||
"""
|
||||
Soil class
|
||||
"""
|
||||
def __init__(self, name, roughness, dry_conductivity, dry_density, dry_specific_heat, thermal_absorptance,
|
||||
solar_absorptance, visible_absorptance, saturation_volumetric_moisture_content,
|
||||
residual_volumetric_moisture_content):
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
"""
|
||||
Vegetation class
|
||||
Vegetation module
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
|
@ -11,6 +11,9 @@ from hub.city_model_structure.greenery.plant import Plant
|
|||
|
||||
|
||||
class Vegetation:
|
||||
"""
|
||||
Vegetation class
|
||||
"""
|
||||
def __init__(self, name, soil, soil_thickness, plants):
|
||||
self._name = name
|
||||
self._management = None
|
||||
|
|
0
hub/city_model_structure/iot/__init__.py
Normal file
0
hub/city_model_structure/iot/__init__.py
Normal file
|
@ -7,6 +7,9 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
|||
|
||||
|
||||
class SensorMeasure:
|
||||
"""
|
||||
Sensor measure class
|
||||
"""
|
||||
def __init__(self, latitude, longitude, utc_timestamp, value):
|
||||
self._latitude = latitude
|
||||
self._longitude = longitude
|
||||
|
|
|
@ -9,6 +9,9 @@ from enum import Enum
|
|||
|
||||
|
||||
class SensorType(Enum):
|
||||
"""
|
||||
Sensor type enumeration
|
||||
"""
|
||||
HUMIDITY = 0
|
||||
TEMPERATURE = 1
|
||||
CO2 = 2
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
"""
|
||||
Station
|
||||
Station module
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||
|
@ -10,6 +10,9 @@ from hub.city_model_structure.iot.sensor import Sensor
|
|||
|
||||
|
||||
class Station:
|
||||
"""
|
||||
Station class
|
||||
"""
|
||||
def __init__(self, station_id=None, _mobile=False):
|
||||
self._id = station_id
|
||||
self._mobile = _mobile
|
||||
|
|
0
hub/city_model_structure/transport/__init__.py
Normal file
0
hub/city_model_structure/transport/__init__.py
Normal file
0
hub/exports/__init__.py
Normal file
0
hub/exports/__init__.py
Normal file
0
hub/exports/building_energy/__init__.py
Normal file
0
hub/exports/building_energy/__init__.py
Normal file
|
@ -93,7 +93,7 @@ class EnergyAde:
|
|||
|
||||
file_name = self._city.name + '_ade.gml'
|
||||
file_path = Path(self._path / file_name).resolve()
|
||||
with open(file_path, 'w') as file:
|
||||
with open(file_path, 'w', encoding='utf8') as file:
|
||||
file.write(xmltodict.unparse(energy_ade, pretty=True, short_empty_elements=True))
|
||||
|
||||
@staticmethod
|
||||
|
|
|
@ -247,16 +247,16 @@ class Idf:
|
|||
_new_field += f' {self.idf_day_types[day_type]}'
|
||||
_kwargs[f'Field_{j * 25 + 2}'] = f'For:{_new_field}'
|
||||
counter += 1
|
||||
for i in range(0, len(_val)):
|
||||
for i, _ in enumerate(_val):
|
||||
_kwargs[f'Field_{j * 25 + 3 + i}'] = f'Until: {i + 1:02d}:00,{_val[i]}'
|
||||
counter += 1
|
||||
_kwargs[f'Field_{counter + 1}'] = f'For AllOtherDays'
|
||||
_kwargs[f'Field_{counter + 2}'] = f'Until: 24:00,0.0'
|
||||
_kwargs[f'Field_{counter + 1}'] = 'For AllOtherDays'
|
||||
_kwargs[f'Field_{counter + 2}'] = 'Until: 24:00,0.0'
|
||||
self._idf.newidfobject(self._COMPACT_SCHEDULE, **_kwargs)
|
||||
|
||||
def _write_schedules_file(self, usage, schedule):
|
||||
file_name = str((Path(self._output_path) / f'{schedule.type} schedules {usage}.dat').resolve())
|
||||
with open(file_name, 'w') as file:
|
||||
with open(file_name, 'w', encoding='utf8') as file:
|
||||
for value in schedule.values:
|
||||
file.write(f'{str(value)},\n')
|
||||
return file_name
|
||||
|
@ -284,12 +284,14 @@ class Idf:
|
|||
if schedule.Name == f'{schedule_type} schedules {usage}':
|
||||
return
|
||||
file_name = self._write_schedules_file(usage, new_schedules[0])
|
||||
return self._add_file_schedule(usage, new_schedules[0], file_name)
|
||||
else:
|
||||
self._add_file_schedule(usage, new_schedules[0], file_name)
|
||||
return
|
||||
|
||||
for schedule in self._idf.idfobjects[self._HOURLY_SCHEDULE]:
|
||||
if schedule.Name == f'{schedule_type} schedules {usage}':
|
||||
return
|
||||
return self._add_standard_compact_hourly_schedule(usage, schedule_type, new_schedules)
|
||||
self._add_standard_compact_hourly_schedule(usage, schedule_type, new_schedules)
|
||||
return
|
||||
|
||||
def _add_construction(self, thermal_boundary):
|
||||
vegetation_name = f'{thermal_boundary.construction_name}_{thermal_boundary.parent_surface.vegetation.name}'
|
||||
|
|
0
hub/exports/building_energy/insel/__init__.py
Normal file
0
hub/exports/building_energy/insel/__init__.py
Normal file
|
@ -27,7 +27,9 @@ _NUMBER_DAYS_PER_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
|||
|
||||
|
||||
class InselMonthlyEnergyBalance:
|
||||
|
||||
"""
|
||||
Insel monthly energy balance class
|
||||
"""
|
||||
def __init__(self, city, path, radiation_calculation_method='sra', weather_format='epw'):
|
||||
self._city = city
|
||||
self._path = path
|
||||
|
@ -44,7 +46,7 @@ class InselMonthlyEnergyBalance:
|
|||
if building.internal_zones is not None:
|
||||
for internal_zone in building.internal_zones:
|
||||
if internal_zone.thermal_zones is None:
|
||||
logging.error(f'Building {building.name} has missing values. Monthly Energy Balance cannot be processed\n')
|
||||
logging.warning(f'Building %s has missing values. Monthly Energy Balance cannot be processed', building.name)
|
||||
break
|
||||
self._contents.append(
|
||||
self._generate_meb_template(building, output_path, self._radiation_calculation_method, self._weather_format)
|
||||
|
@ -65,32 +67,32 @@ class InselMonthlyEnergyBalance:
|
|||
def _export(self):
|
||||
for i_file, content in enumerate(self._contents):
|
||||
file_name = self._insel_files_paths[i_file]
|
||||
with open(Path(self._path / file_name).resolve(), 'w') as insel_file:
|
||||
with open(Path(self._path / file_name).resolve(), 'w', encoding='utf8') as insel_file:
|
||||
insel_file.write(content)
|
||||
return
|
||||
|
||||
def _sanity_check(self):
|
||||
levels_of_detail = self._city.level_of_detail
|
||||
if levels_of_detail.geometry is None:
|
||||
raise Exception(f'Level of detail of geometry not assigned')
|
||||
raise AttributeError('Level of detail of geometry not assigned')
|
||||
if levels_of_detail.geometry < 1:
|
||||
raise Exception(f'Level of detail of geometry = {levels_of_detail.geometry}. Required minimum level 0.5')
|
||||
raise AttributeError(f'Level of detail of geometry = {levels_of_detail.geometry}. Required minimum level 0.5')
|
||||
if levels_of_detail.construction is None:
|
||||
raise Exception(f'Level of detail of construction not assigned')
|
||||
raise AttributeError('Level of detail of construction not assigned')
|
||||
if levels_of_detail.construction < 1:
|
||||
raise Exception(f'Level of detail of construction = {levels_of_detail.construction}. Required minimum level 1')
|
||||
raise AttributeError(f'Level of detail of construction = {levels_of_detail.construction}. Required minimum level 1')
|
||||
if levels_of_detail.usage is None:
|
||||
raise Exception(f'Level of detail of usage not assigned')
|
||||
raise AttributeError('Level of detail of usage not assigned')
|
||||
if levels_of_detail.usage < 1:
|
||||
raise Exception(f'Level of detail of usage = {levels_of_detail.usage}. Required minimum level 1')
|
||||
raise AttributeError(f'Level of detail of usage = {levels_of_detail.usage}. Required minimum level 1')
|
||||
if levels_of_detail.weather is None:
|
||||
raise Exception(f'Level of detail of weather not assigned')
|
||||
raise AttributeError('Level of detail of weather not assigned')
|
||||
if levels_of_detail.weather < 1:
|
||||
raise Exception(f'Level of detail of weather = {levels_of_detail.weather}. Required minimum level 1')
|
||||
raise AttributeError(f'Level of detail of weather = {levels_of_detail.weather}. Required minimum level 1')
|
||||
if levels_of_detail.surface_radiation is None:
|
||||
raise Exception(f'Level of detail of surface radiation not assigned')
|
||||
raise AttributeError('Level of detail of surface radiation not assigned')
|
||||
if levels_of_detail.surface_radiation < 1:
|
||||
raise Exception(f'Level of detail of surface radiation = {levels_of_detail.surface_radiation}. '
|
||||
raise AttributeError(f'Level of detail of surface radiation = {levels_of_detail.surface_radiation}. '
|
||||
f'Required minimum level 1')
|
||||
|
||||
@staticmethod
|
||||
|
|
|
@ -5,8 +5,8 @@ Copyright © 2022 Concordia CERC group
|
|||
Project Coder Pilar Monsalvete Alvarez de uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
from hub.exports.building_energy.energy_ade import EnergyAde
|
||||
from hub.exports.building_energy.idf import Idf
|
||||
from hub.exports.building_energy.insel.insel_monthly_energy_balance import InselMonthlyEnergyBalance
|
||||
|
|
|
@ -49,7 +49,7 @@ class EnergySystemsExportFactory:
|
|||
if self._source == 'air':
|
||||
return AirSourceHPExport(self._base_path, self._city, self._output_path, self._sim_type, self._demand_path)\
|
||||
.execute_insel(self._handler, self._hp_model, self._data_type)
|
||||
elif self._source == 'water':
|
||||
|
||||
return WaterToWaterHPExport(self._base_path, self._city, self._output_path, self._sim_type, self._demand_path)\
|
||||
.execute_insel(self._handler, self._hp_model)
|
||||
|
||||
|
|
|
@ -5,8 +5,8 @@ Copyright © 2022 Concordia CERC group
|
|||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||
"""
|
||||
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
from hub.exports.formats.obj import Obj
|
||||
from hub.exports.formats.simplified_radiosity_algorithm import SimplifiedRadiosityAlgorithm
|
||||
from hub.exports.formats.stl import Stl
|
||||
|
|
0
hub/exports/formats/__init__.py
Normal file
0
hub/exports/formats/__init__.py
Normal file
0
hub/helpers/__init__.py
Normal file
0
hub/helpers/__init__.py
Normal file
0
hub/helpers/data/__init__.py
Normal file
0
hub/helpers/data/__init__.py
Normal file
0
hub/imports/construction/__init__.py
Normal file
0
hub/imports/construction/__init__.py
Normal file
0
hub/imports/construction/helpers/__init__.py
Normal file
0
hub/imports/construction/helpers/__init__.py
Normal file
|
@ -85,7 +85,7 @@ class ConstructionHelper:
|
|||
:return: str
|
||||
"""
|
||||
reference_city = ConstructionHelper.city_to_reference_city(city)
|
||||
if reference_city not in ConstructionHelper._reference_city_to_nrel_climate_zone.keys():
|
||||
if reference_city not in ConstructionHelper._reference_city_to_nrel_climate_zone:
|
||||
reference_city = 'Baltimore'
|
||||
return ConstructionHelper._reference_city_to_nrel_climate_zone[reference_city]
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ class StoreysGeneration:
|
|||
return [storey.thermal_zone]
|
||||
|
||||
if number_of_storeys == 0:
|
||||
raise Exception('Number of storeys cannot be 0')
|
||||
raise ArithmeticError('Number of storeys cannot be 0')
|
||||
|
||||
storeys = []
|
||||
surfaces_child_last_storey = []
|
||||
|
@ -106,7 +106,7 @@ class StoreysGeneration:
|
|||
neighbours = ['storey_' + str(number_of_storeys - 2), None]
|
||||
volume = self._building.volume - total_volume
|
||||
if volume < 0:
|
||||
raise Exception('Error in storeys creation, volume of last storey cannot be lower that 0')
|
||||
raise ArithmeticError('Error in storeys creation, volume of last storey cannot be lower that 0')
|
||||
storeys.append(Storey(name, surfaces_child_last_storey, neighbours, volume, self._internal_zone, self._floor_area))
|
||||
|
||||
for storey in storeys:
|
||||
|
|
0
hub/imports/energy_systems/__init__.py
Normal file
0
hub/imports/energy_systems/__init__.py
Normal file
|
@ -7,14 +7,14 @@ contributor Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
|||
"""
|
||||
import io
|
||||
|
||||
import pandas as pd
|
||||
import itertools
|
||||
from typing import List
|
||||
from typing import Dict
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from scipy.optimize import curve_fit
|
||||
from hub.city_model_structure.energy_systems.air_source_hp import AirSourceHP
|
||||
from hub.city_model_structure.energy_system import EnergySystem
|
||||
from scipy.optimize import curve_fit
|
||||
import numpy as np
|
||||
from typing import List
|
||||
import itertools
|
||||
|
||||
|
||||
class AirSourceHeatPumpParameters:
|
||||
|
@ -24,7 +24,7 @@ class AirSourceHeatPumpParameters:
|
|||
|
||||
def __init__(self, city, base_path):
|
||||
self._city = city
|
||||
self._base_path = (base_path / 'heat_pumps/air_source.xlsx')
|
||||
self._base_path = (base_path / 'heat_pumps/air_source.xlsx').resolve()
|
||||
|
||||
def _read_file(self) -> Dict:
|
||||
"""
|
||||
|
@ -38,7 +38,7 @@ class AirSourceHeatPumpParameters:
|
|||
cooling_data = {}
|
||||
heating_data = {}
|
||||
|
||||
for sheet, dataframe in xl_file.items():
|
||||
for sheet, _ in xl_file.items():
|
||||
if 'Summary' in sheet:
|
||||
continue
|
||||
|
||||
|
@ -68,7 +68,7 @@ class AirSourceHeatPumpParameters:
|
|||
Enriches the city with information from file
|
||||
"""
|
||||
heat_pump_data = self._read_file()
|
||||
for (k_cool, v_cool), (k_heat, v_heat) in zip(heat_pump_data["cooling"].items(), heat_pump_data["heating"].items()):
|
||||
for (k_cool, v_cool), (_, v_heat) in zip(heat_pump_data["cooling"].items(), heat_pump_data["heating"].items()):
|
||||
heat_pump = AirSourceHP()
|
||||
heat_pump.model = k_cool
|
||||
h_data = self._extract_heat_pump_data(v_heat)
|
||||
|
@ -80,7 +80,7 @@ class AirSourceHeatPumpParameters:
|
|||
heat_pump.heating_comp_power = h_data[1]
|
||||
heat_pump.heating_capacity_coff = self._compute_coefficients(h_data)
|
||||
|
||||
energy_system = EnergySystem('{} capacity heat pump'.format(heat_pump.model), [])
|
||||
energy_system = EnergySystem(f'{heat_pump.model} capacity heat pump', [])
|
||||
energy_system.air_source_hp = heat_pump
|
||||
self._city.add_city_object(energy_system)
|
||||
return self._city
|
||||
|
|
|
@ -43,7 +43,8 @@ class MontrealCustomEnergySystemParameters:
|
|||
try:
|
||||
archetype = self._search_archetypes(montreal_custom_catalog, archetype_name)
|
||||
except KeyError:
|
||||
logging.error(f'Building {building.name} has unknown energy system archetype for system name: {archetype_name}')
|
||||
logging.error('Building %s has unknown energy system archetype for system name %s', building.name,
|
||||
archetype_name)
|
||||
continue
|
||||
|
||||
building_systems = []
|
||||
|
@ -58,7 +59,7 @@ class MontrealCustomEnergySystemParameters:
|
|||
energy_system.demand_types = _hub_demand_types
|
||||
_generation_system = GenericGenerationSystem()
|
||||
archetype_generation_equipment = equipment.generation_system
|
||||
_type = str(equipment.name).split('_')[0]
|
||||
_type = str(equipment.name).split('_', maxsplit=1)[0]
|
||||
_generation_system.type = Dictionaries().montreal_system_to_hub_energy_generation_system[
|
||||
_type]
|
||||
_generation_system.fuel_type = archetype_generation_equipment.fuel_type
|
||||
|
|
|
@ -23,7 +23,7 @@ class WaterToWaterHPParameters:
|
|||
|
||||
def __init__(self, city, base_path):
|
||||
self._city = city
|
||||
self._base_path = (base_path / 'heat_pumps/water_to_water.xlsx')
|
||||
self._base_path = (base_path / 'heat_pumps/water_to_water.xlsx').resolve()
|
||||
|
||||
def _read_file(self) -> Dict:
|
||||
# todo: this method is keeping the excel file open and should be either corrected or removed
|
||||
|
@ -38,7 +38,7 @@ class WaterToWaterHPParameters:
|
|||
'335': [6.62, 9.97, 12.93],
|
||||
}
|
||||
|
||||
for sheet, dataframe in heat_pump_dfs.items():
|
||||
for sheet, _ in heat_pump_dfs.items():
|
||||
|
||||
df = heat_pump_dfs[sheet].dropna(axis=1, how='all')
|
||||
df = df.iloc[3:, 6:35]
|
||||
|
|
0
hub/imports/geometry/__init__.py
Normal file
0
hub/imports/geometry/__init__.py
Normal file
|
@ -41,7 +41,7 @@ class CityGml:
|
|||
|
||||
self._lower_corner = None
|
||||
self._upper_corner = None
|
||||
with open(path) as gml:
|
||||
with open(path, 'r', encoding='utf8') as gml:
|
||||
# Clean the namespaces is an important task to prevent wrong ns:field due poor citygml_classes implementations
|
||||
force_list = ('cityObjectMember', 'curveMember', 'boundedBy', 'surfaceMember', 'consistsOfBuildingPart')
|
||||
self._gml = xmltodict.parse(gml.read(), process_namespaces=True, xml_attribs=True, namespaces={
|
||||
|
@ -123,7 +123,7 @@ class CityGml:
|
|||
year_of_construction = city_object[self._year_of_construction_field]
|
||||
if self._function_field in city_object:
|
||||
function = city_object[self._function_field]
|
||||
if type(function) != str:
|
||||
if not isinstance(function, str):
|
||||
function = function['#text']
|
||||
if self._function_to_hub is not None:
|
||||
# use the transformation dictionary to retrieve the proper function
|
||||
|
|
0
hub/imports/geometry/citygml_classes/__init__.py
Normal file
0
hub/imports/geometry/citygml_classes/__init__.py
Normal file
|
@ -74,7 +74,7 @@ class CityGmlLod2(CityGmlBase):
|
|||
gml_points = gml_points_string.lstrip(' ')
|
||||
solid_points = GeometryHelper.points_from_string(GeometryHelper.remove_last_point_from_string(gml_points))
|
||||
polygon = Polygon(solid_points)
|
||||
return Surface(polygon, polygon, surface_type=GeometryHelper.gml_surface_to_libs(surface_type))
|
||||
return Surface(polygon, polygon, surface_type=GeometryHelper.gml_surface_to_hub(surface_type))
|
||||
|
||||
@classmethod
|
||||
def _multi_curve(cls, city_object_member):
|
||||
|
|
|
@ -47,7 +47,7 @@ class Geojson:
|
|||
self._year_of_construction_field = year_of_construction_field
|
||||
self._function_field = function_field
|
||||
self._function_to_hub = function_to_hub
|
||||
with open(path) as json_file:
|
||||
with open(path, 'r', encoding='utf8') as json_file:
|
||||
self._geojson = json.loads(json_file.read())
|
||||
|
||||
def _save_bounds(self, x, y):
|
||||
|
@ -98,8 +98,7 @@ class Geojson:
|
|||
GeometryHelper.distance_between_points(line[0], neighbour_line[1])) / 2
|
||||
percentage_ground = line_shared / GeometryHelper.distance_between_points(line[0], line[1])
|
||||
percentage_height = neighbour_height / building.max_height
|
||||
if percentage_height > 1:
|
||||
percentage_height = 1
|
||||
percentage_height = min(percentage_height, 1)
|
||||
percentage += percentage_ground * percentage_height
|
||||
wall.percentage_shared = percentage
|
||||
|
||||
|
@ -215,7 +214,7 @@ class Geojson:
|
|||
building.add_alias(alias)
|
||||
if extrusion_height == 0:
|
||||
return building
|
||||
else:
|
||||
|
||||
volume = 0
|
||||
for ground in building.grounds:
|
||||
volume += ground.solid_polygon.area * extrusion_height
|
||||
|
@ -289,7 +288,7 @@ class Geojson:
|
|||
building.add_alias(alias)
|
||||
if extrusion_height == 0:
|
||||
return building
|
||||
else:
|
||||
|
||||
volume = 0
|
||||
for ground in building.grounds:
|
||||
volume += ground.solid_polygon.area * extrusion_height
|
||||
|
|
|
@ -58,7 +58,7 @@ class GPandas:
|
|||
if self._city is None:
|
||||
self._city = City(self._lower_corner, self._upper_corner, self._srs_name)
|
||||
lod = 0
|
||||
for scene_index, bldg in self._scene.iterrows():
|
||||
for _, bldg in self._scene.iterrows():
|
||||
polygon = bldg.geometry
|
||||
height = float(bldg['height'])
|
||||
building_mesh = trimesh.creation.extrude_polygon(polygon, height)
|
||||
|
@ -72,7 +72,7 @@ class GPandas:
|
|||
else:
|
||||
function = cte.INDUSTRY
|
||||
surfaces = []
|
||||
for face_index, face in enumerate(building_mesh.faces):
|
||||
for _, face in enumerate(building_mesh.faces):
|
||||
points = []
|
||||
for vertex_index in face:
|
||||
points.append(building_mesh.vertices[vertex_index])
|
||||
|
|
0
hub/imports/geometry/helpers/__init__.py
Normal file
0
hub/imports/geometry/helpers/__init__.py
Normal file
|
@ -8,7 +8,7 @@ import math
|
|||
import sys
|
||||
|
||||
import numpy as np
|
||||
|
||||
from numpy import ndarray
|
||||
|
||||
class GeometryHelper:
|
||||
"""
|
||||
|
@ -26,7 +26,7 @@ class GeometryHelper:
|
|||
return points
|
||||
|
||||
@staticmethod
|
||||
def gml_surface_to_libs(surface):
|
||||
def gml_surface_to_hub(surface):
|
||||
"""
|
||||
Transform citygml surface names into hub names
|
||||
"""
|
||||
|
@ -38,18 +38,30 @@ class GeometryHelper:
|
|||
|
||||
@staticmethod
|
||||
def points_from_string(coordinates) -> np.ndarray:
|
||||
"""
|
||||
Creates a ndarray from a string
|
||||
:return: [Point]
|
||||
"""
|
||||
points = np.fromstring(coordinates, dtype=float, sep=' ')
|
||||
points = GeometryHelper.to_points_matrix(points)
|
||||
return points
|
||||
|
||||
@staticmethod
|
||||
def remove_last_point_from_string(points):
|
||||
def remove_last_point_from_string(points) -> [ndarray]:
|
||||
"""
|
||||
Return the point list without the last element
|
||||
:return [ndarray]
|
||||
"""
|
||||
array = points.split(' ')
|
||||
res = " "
|
||||
return res.join(array[0:len(array) - 3])
|
||||
|
||||
@staticmethod
|
||||
def invert_points(points):
|
||||
def invert_points(points) -> [ndarray]:
|
||||
"""
|
||||
Invert the point list
|
||||
:return: [ndarray]
|
||||
"""
|
||||
res = []
|
||||
for point in points:
|
||||
res.insert(0, point)
|
||||
|
|
|
@ -19,7 +19,7 @@ class Obj:
|
|||
"""
|
||||
def __init__(self, path):
|
||||
self._city = None
|
||||
with open(path, 'r') as file:
|
||||
with open(path, 'r', encoding='utf8') as file:
|
||||
self._scene = trimesh.exchange.load.load(file, file_type='obj', force='scene')
|
||||
self._corners = self._scene.bounds_corners
|
||||
_bound_corner_min = None
|
||||
|
@ -70,7 +70,6 @@ class Obj:
|
|||
obj = scene[key]
|
||||
surfaces = []
|
||||
for face in obj.faces:
|
||||
# todo: review for obj with windows
|
||||
points = []
|
||||
for vertex_index in face:
|
||||
points.append(obj.vertices[vertex_index])
|
||||
|
|
|
@ -6,8 +6,7 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.capip
|
|||
"""
|
||||
import numpy as np
|
||||
from rhino3dm import *
|
||||
from rhino3dm._rhino3dm import Extrusion
|
||||
from rhino3dm._rhino3dm import MeshType
|
||||
from rhino3dm._rhino3dm import Extrusion, MeshType, File3dm
|
||||
|
||||
from hub.city_model_structure.attributes.point import Point
|
||||
from hub.city_model_structure.attributes.polygon import Polygon
|
||||
|
@ -19,6 +18,9 @@ from hub.imports.geometry.helpers.geometry_helper import GeometryHelper
|
|||
|
||||
|
||||
class Rhino:
|
||||
"""
|
||||
Rhino class
|
||||
"""
|
||||
def __init__(self, path):
|
||||
self._model = File3dm.Read(str(path))
|
||||
max_float = float(ConfigurationHelper().max_coordinate)
|
||||
|
@ -85,6 +87,10 @@ class Rhino:
|
|||
|
||||
@property
|
||||
def city(self) -> City:
|
||||
"""
|
||||
Return a city based in the rhino file
|
||||
:return: City
|
||||
"""
|
||||
buildings = []
|
||||
city_objects = [] # building and "windows"
|
||||
windows = []
|
||||
|
|
|
@ -95,3 +95,12 @@ class GeometryFactory:
|
|||
:return: City
|
||||
"""
|
||||
return getattr(self, self._file_type, lambda: None)
|
||||
|
||||
@property
|
||||
def city_debug(self) -> City:
|
||||
"""
|
||||
Enrich the city given to the class using the class given handler
|
||||
:return: City
|
||||
"""
|
||||
print('rhino')
|
||||
return Rhino(self._path).city
|
||||
|
|
0
hub/imports/results/__init__.py
Normal file
0
hub/imports/results/__init__.py
Normal file
|
@ -21,12 +21,15 @@ class InselHeatPumpEnergyDemand:
|
|||
"""
|
||||
self._city = city
|
||||
self._hp_model = hp_model
|
||||
with open(Path(base_path).resolve()) as csv_file:
|
||||
with open(Path(base_path).resolve(), 'r', encoding='utf8') as csv_file:
|
||||
df = pd.read_csv(csv_file)
|
||||
self._monthly_electricity_demand = df.iloc[:, 1]
|
||||
self._monthly_fossil_fuel_consumption = df.iloc[:, 2]
|
||||
|
||||
def enrich(self):
|
||||
"""
|
||||
Enrich the city with the heat pump information
|
||||
"""
|
||||
for energy_system in self._city.energy_systems:
|
||||
if energy_system.air_source_hp is not None:
|
||||
if energy_system.air_source_hp.model == self._hp_model:
|
||||
|
@ -35,4 +38,3 @@ class InselHeatPumpEnergyDemand:
|
|||
if energy_system.water_to_water_hp is not None:
|
||||
if energy_system.water_to_water_hp.model == self._hp_model:
|
||||
energy_system.water_to_water_hp.hp_monthly_electricity_demand = self._monthly_electricity_demand
|
||||
|
||||
|
|
|
@ -5,8 +5,9 @@ Copyright © 2022 Concordia CERC group
|
|||
Project Coder Guillermo.GutierrezMorote@concordia.ca
|
||||
"""
|
||||
from pathlib import Path
|
||||
import pandas as pd
|
||||
import csv
|
||||
import pandas as pd
|
||||
|
||||
import hub.helpers.constants as cte
|
||||
|
||||
|
||||
|
@ -23,7 +24,7 @@ class InselMonthlyEnergyBalance:
|
|||
def _conditioning_demand(insel_output_file_path):
|
||||
heating = []
|
||||
cooling = []
|
||||
with open(Path(insel_output_file_path).resolve()) as csv_file:
|
||||
with open(Path(insel_output_file_path).resolve(), 'r', encoding='utf8') as csv_file:
|
||||
csv_reader = csv.reader(csv_file)
|
||||
for line in csv_reader:
|
||||
demand = str(line).replace("['", '').replace("']", '').split()
|
||||
|
@ -108,6 +109,10 @@ class InselMonthlyEnergyBalance:
|
|||
)
|
||||
|
||||
def enrich(self):
|
||||
"""
|
||||
Enrich the city by using the insel monthly energy balance output files
|
||||
:return: None
|
||||
"""
|
||||
for building in self._city.buildings:
|
||||
file_name = building.name + '.out'
|
||||
insel_output_file_path = Path(self._base_path / file_name).resolve()
|
||||
|
|
|
@ -4,9 +4,9 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Guillermo.GutierrezMorote@concordia.ca
|
||||
"""
|
||||
import calendar as cal
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import calendar as cal
|
||||
import hub.helpers.constants as cte
|
||||
|
||||
|
||||
|
@ -18,7 +18,7 @@ class SimplifiedRadiosityAlgorithm:
|
|||
|
||||
self._city = city
|
||||
self._base_path = base_path
|
||||
self._input_file_path = (self._base_path / f'{self._city.name}_sra_SW.out')
|
||||
self._input_file_path = (self._base_path / f'{self._city.name}_sra_SW.out').resolve()
|
||||
self._month_hour = self._month_hour_data_frame
|
||||
self._results = self._read_results()
|
||||
self._radiation_list = []
|
||||
|
@ -48,8 +48,8 @@ class SimplifiedRadiosityAlgorithm:
|
|||
def _read_results(self):
|
||||
try:
|
||||
return pd.read_csv(self._input_file_path, sep='\s+', header=0)
|
||||
except Exception:
|
||||
raise Exception('No SRA output file found')
|
||||
except FileNotFoundError as err:
|
||||
raise FileNotFoundError('No SRA output file found') from err
|
||||
|
||||
@property
|
||||
def _radiation(self) -> []:
|
||||
|
|
0
hub/imports/usage/__init__.py
Normal file
0
hub/imports/usage/__init__.py
Normal file
|
@ -5,9 +5,8 @@ Copyright © 2022 Concordia CERC group
|
|||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
import copy
|
||||
import numpy
|
||||
import logging
|
||||
|
||||
import numpy
|
||||
import hub.helpers.constants as cte
|
||||
from hub.helpers.dictionaries import Dictionaries
|
||||
from hub.city_model_structure.building_demand.usage import Usage
|
||||
|
@ -40,16 +39,16 @@ class ComnetUsageParameters:
|
|||
try:
|
||||
archetype_usage = self._search_archetypes(comnet_catalog, usage_name)
|
||||
except KeyError:
|
||||
logging.error(f'Building {building.name} has unknown usage archetype for usage: {usage_name}')
|
||||
logging.error('Building %s has unknown usage archetype for usage %s', building.name, usage_name)
|
||||
continue
|
||||
|
||||
for internal_zone in building.internal_zones:
|
||||
if internal_zone.area is None:
|
||||
raise Exception('Internal zone area not defined, ACH cannot be calculated')
|
||||
raise TypeError('Internal zone area not defined, ACH cannot be calculated')
|
||||
if internal_zone.volume is None:
|
||||
raise Exception('Internal zone volume not defined, ACH cannot be calculated')
|
||||
raise TypeError('Internal zone volume not defined, ACH cannot be calculated')
|
||||
if internal_zone.area <= 0:
|
||||
raise Exception('Internal zone area is zero, ACH cannot be calculated')
|
||||
raise TypeError('Internal zone area is zero, ACH cannot be calculated')
|
||||
volume_per_area = internal_zone.volume / internal_zone.area
|
||||
usage = Usage()
|
||||
usage.name = usage_name
|
||||
|
@ -160,7 +159,7 @@ class ComnetUsageParameters:
|
|||
@staticmethod
|
||||
def _calculate_internal_gains(archetype):
|
||||
|
||||
_DAYS = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY, cte.SATURDAY, cte.SUNDAY, cte.HOLIDAY]
|
||||
_days = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY, cte.SATURDAY, cte.SUNDAY, cte.HOLIDAY]
|
||||
_number_of_days_per_type = [51, 50, 50, 50, 50, 52, 52, 10]
|
||||
|
||||
_mean_internal_gain = InternalGain()
|
||||
|
@ -174,13 +173,13 @@ class ComnetUsageParameters:
|
|||
_latent_heat_gain = archetype.occupancy.latent_internal_gain
|
||||
_convective_heat_gain = archetype.occupancy.sensible_convective_internal_gain
|
||||
_radiative_heat_gain = archetype.occupancy.sensible_radiative_internal_gain
|
||||
_total_heat_gain = (_latent_heat_gain + _convective_heat_gain + _radiative_heat_gain)
|
||||
_total_heat_gain = _latent_heat_gain + _convective_heat_gain + _radiative_heat_gain
|
||||
|
||||
_schedule_values = numpy.zeros([24, 8])
|
||||
_sum = 0
|
||||
for day, _schedule in enumerate(archetype.occupancy.schedules):
|
||||
for v, value in enumerate(_schedule.values):
|
||||
_schedule_values[v, day] = value * _total_heat_gain
|
||||
for v_index, value in enumerate(_schedule.values):
|
||||
_schedule_values[v_index, day] = value * _total_heat_gain
|
||||
_sum += value * _total_heat_gain * _number_of_days_per_type[day]
|
||||
|
||||
_total_heat_gain += archetype.lighting.density + archetype.appliances.density
|
||||
|
@ -198,13 +197,13 @@ class ComnetUsageParameters:
|
|||
)
|
||||
|
||||
for day, _schedule in enumerate(archetype.lighting.schedules):
|
||||
for v, value in enumerate(_schedule.values):
|
||||
_schedule_values[v, day] += value * archetype.lighting.density
|
||||
for v_index, value in enumerate(_schedule.values):
|
||||
_schedule_values[v_index, day] += value * archetype.lighting.density
|
||||
_sum += value * archetype.lighting.density * _number_of_days_per_type[day]
|
||||
|
||||
for day, _schedule in enumerate(archetype.appliances.schedules):
|
||||
for v, value in enumerate(_schedule.values):
|
||||
_schedule_values[v, day] += value * archetype.appliances.density
|
||||
for v_index, value in enumerate(_schedule.values):
|
||||
_schedule_values[v_index, day] += value * archetype.appliances.density
|
||||
_sum += value * archetype.appliances.density * _number_of_days_per_type[day]
|
||||
|
||||
_latent_fraction = 0
|
||||
|
@ -218,9 +217,9 @@ class ComnetUsageParameters:
|
|||
_average_internal_gain = _sum / _total_heat_gain
|
||||
|
||||
_schedules = []
|
||||
for day in range(0, len(_DAYS)):
|
||||
for day, current_day in enumerate(_days):
|
||||
_schedule = copy.deepcopy(_base_schedule)
|
||||
_schedule.day_types = [_DAYS[day]]
|
||||
_schedule.day_types = [current_day]
|
||||
_schedule.values = _schedule_values[:day]
|
||||
_schedules.append(_schedule)
|
||||
|
||||
|
|
|
@ -39,36 +39,36 @@ class NrcanUsageParameters:
|
|||
try:
|
||||
archetype_usage = self._search_archetypes(nrcan_catalog, usage_name)
|
||||
except KeyError:
|
||||
logging.error(f'Building {building.name} has unknown usage archetype for usage: {usage_name}\n')
|
||||
logging.error('Building %s has unknown usage archetype for usage %s', building.name, usage_name)
|
||||
continue
|
||||
|
||||
comnet_usage_name = Dictionaries().hub_usage_to_comnet_usage[building.function]
|
||||
try:
|
||||
comnet_archetype_usage = self._search_archetypes(comnet_catalog, comnet_usage_name)
|
||||
except KeyError:
|
||||
logging.error(f'Building {building.name} has unknown usage archetype for usage: {comnet_usage_name}\n')
|
||||
logging.error('Building %s has unknown usage archetype for usage %s', building.name, comnet_usage_name)
|
||||
continue
|
||||
|
||||
for internal_zone in building.internal_zones:
|
||||
if len(building.internal_zones) > 1:
|
||||
volume_per_area = 0
|
||||
if internal_zone.area is None:
|
||||
logging.error(f'Building {building.name} has internal zone area not defined, '
|
||||
f'ACH cannot be calculated for usage: {usage_name}\n')
|
||||
logging.error('Building %s has internal zone area not defined, ACH cannot be calculated for usage %s',
|
||||
building.name, usage_name)
|
||||
continue
|
||||
if internal_zone.volume is None:
|
||||
logging.error(f'Building {building.name} has internal zone volume not defined, '
|
||||
f'ACH cannot be calculated for usage: {usage_name}\n')
|
||||
logging.error('Building %s has internal zone volume not defined, ACH cannot be calculated for usage %s',
|
||||
building.name, usage_name)
|
||||
continue
|
||||
if internal_zone.area <= 0:
|
||||
logging.error(f'Building {building.name} has internal zone area equal to 0, '
|
||||
f'ACH cannot be calculated for usage: {usage_name}\n')
|
||||
logging.error('Building %s has internal zone area equal to 0, ACH cannot be calculated for usage %s',
|
||||
building.name, usage_name)
|
||||
continue
|
||||
volume_per_area += internal_zone.volume / internal_zone.area
|
||||
else:
|
||||
if building.storeys_above_ground is None:
|
||||
logging.error(f'Building {building.name} no number of storeys assigned, '
|
||||
f'ACH cannot be calculated for usage: {usage_name}\n')
|
||||
logging.error('Building %s no number of storeys assigned, ACH cannot be calculated for usage %s',
|
||||
building.name, usage_name)
|
||||
continue
|
||||
volume_per_area = building.volume / building.floor_area / building.storeys_above_ground
|
||||
|
||||
|
|
0
hub/imports/weather/__init__.py
Normal file
0
hub/imports/weather/__init__.py
Normal file
|
@ -22,7 +22,7 @@ class EpwWeatherParameters:
|
|||
self._path = Path(path / file_name)
|
||||
|
||||
try:
|
||||
file = open(self._path, 'r')
|
||||
with open(self._path, 'r', encoding='utf8') as file:
|
||||
line = file.readline().split(',')
|
||||
city.climate_reference_city = line[1]
|
||||
city.latitude = line[6]
|
||||
|
@ -39,10 +39,9 @@ class EpwWeatherParameters:
|
|||
for j in range(0, 12):
|
||||
temperatures.append(float(line[i*16+j+6]))
|
||||
ground_temperature[depth_measurement_ground_temperature] = temperatures
|
||||
file.close()
|
||||
except SystemExit:
|
||||
logging.error(f'Error: weather file {self._path} not found. Please download it from '
|
||||
f'https://energyplus.net/weather and place it in folder data\\weather\\epw\n')
|
||||
logging.error('Error: weather file %s not found. Please download it from https://energyplus.net/weather and place'
|
||||
' it in folder data\\weather\\epw', self._path)
|
||||
sys.exit()
|
||||
|
||||
try:
|
||||
|
|
0
hub/imports/weather/helpers/__init__.py
Normal file
0
hub/imports/weather/helpers/__init__.py
Normal file
|
@ -6,10 +6,10 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
|||
"""
|
||||
|
||||
import math
|
||||
import hub.helpers.constants as cte
|
||||
import pandas as pd
|
||||
import calendar as cal
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import hub.helpers.constants as cte
|
||||
|
||||
|
||||
class Weather:
|
||||
|
@ -65,6 +65,10 @@ class Weather:
|
|||
return pd.DataFrame(cold_temperature, columns=['epw'])
|
||||
|
||||
def get_monthly_mean_values(self, values):
|
||||
"""
|
||||
Get the monthly mean for the given values
|
||||
:return: float
|
||||
"""
|
||||
out = None
|
||||
if values is not None:
|
||||
if 'month' not in values.columns:
|
||||
|
@ -75,9 +79,17 @@ class Weather:
|
|||
|
||||
@staticmethod
|
||||
def get_yearly_mean_values(values):
|
||||
"""
|
||||
Get the yearly mean for the given values
|
||||
:return: float
|
||||
"""
|
||||
return values.mean()
|
||||
|
||||
def get_total_month(self, values):
|
||||
"""
|
||||
Get the total value the given values
|
||||
:return: float
|
||||
"""
|
||||
out = None
|
||||
if values is not None:
|
||||
if 'month' not in values.columns:
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
"""
|
||||
Persistence package
|
||||
"""
|
6
setup.py
6
setup.py
|
@ -19,6 +19,8 @@ with open(version) as f:
|
|||
exec(f.read(), main_ns)
|
||||
|
||||
|
||||
|
||||
|
||||
setup(
|
||||
name='cerc-hub',
|
||||
version=main_ns['__version__'],
|
||||
|
@ -38,10 +40,14 @@ setup(
|
|||
packages=['hub',
|
||||
'hub.catalog_factories',
|
||||
'hub.catalog_factories.construction',
|
||||
'hub.catalog_factories.cost',
|
||||
'hub.catalog_factories.data_models',
|
||||
'hub.catalog_factories.data_models.construction',
|
||||
'hub.catalog_factories.data_models.cost',
|
||||
'hub.catalog_factories.data_models.energy_systems',
|
||||
'hub.catalog_factories.data_models.greenery',
|
||||
'hub.catalog_factories.data_models.usages',
|
||||
'hub.catalog_factories.energy_systems',
|
||||
'hub.catalog_factories.greenery',
|
||||
'hub.catalog_factories.greenery.ecore_greenery',
|
||||
'hub.catalog_factories.usage',
|
||||
|
|
|
@ -72,7 +72,7 @@ class Control:
|
|||
|
||||
city_file = "tests_data/FZK_Haus_LoD_2.gml"
|
||||
weather_file = 'CAN_PQ_Montreal.Intl.AP.716270_CWEC.epw'
|
||||
output_path = Path('./tests_outputs/').resolve()
|
||||
output_path = Path('tests_outputs/').resolve()
|
||||
self._city = GeometryFactory('citygml',
|
||||
city_file,
|
||||
function_to_hub=Dictionaries().alkis_function_to_hub_function).city
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user