Compare commits

...

28 Commits

Author SHA1 Message Date
6b89008698 Merge branch 'main' into reviewing_hub
# Conflicts:
#	hub/imports/construction/eilat_physics_parameters.py
#	hub/imports/construction/nrcan_physics_parameters.py
2023-08-02 14:35:31 -04:00
0f982df32e Merge pull request 'retrofit_db_changes' (#38) from retrofit_db_changes into main
Reviewed-on: https://nextgenerations-cities.encs.concordia.ca/gitea/CERC/hub/pulls/38
2023-08-02 14:26:14 -04:00
c38b025c2e Correct bd test, add dictionary for custom fuel to hub fuel 2023-08-02 12:43:51 -04:00
4d0f247a83 cost completed 2023-08-01 16:41:37 -04:00
e44abc2f3a Update hub/version.py 2023-07-31 16:12:03 -04:00
421c69e97e add missing file to the setup 2023-07-31 16:11:19 -04:00
2292bff1b8 building info can now be retrieved via application, user and scenario 2023-07-31 16:08:10 -04:00
1abf76125f building info can now be retrieved via application, user and scenario 2023-07-31 12:42:02 -04:00
ce995c375d Merge remote-tracking branch 'origin/main' into retrofit_db_changes 2023-07-31 12:40:29 -04:00
2cc938e416 Update hub/version.py 2023-07-31 12:22:44 -04:00
eb246a18e6 Additional changes, the db_control building info need to be changed 2023-07-28 14:55:06 -04:00
57322e1b19 Merge pull request 'system_catalog_fix' (#37) from system_catalog_fix into main
Reviewed-on: https://nextgenerations-cities.encs.concordia.ca/gitea/CERC/hub/pulls/37
2023-07-28 14:06:43 -04:00
24324988b6 added dictionary from montreal fuel type to hub 2023-07-28 13:18:23 -04:00
ee419b0849 added dictionary from montreal fuel type to hub 2023-07-28 12:26:17 -04:00
f95c45660e persistence changes 2023-07-28 08:25:47 -04:00
4add8b2cff initial changes 2023-07-26 15:03:31 -04:00
5afb60e7c4 Partially correct unit-test 2023-07-25 16:14:52 -04:00
35e50cf551 Partially correct unit-test 2023-07-25 16:00:14 -04:00
066a25bfee Partially correct unit-test 2023-07-25 15:36:49 -04:00
0d63a6c4e9 Update hub/version.py 2023-07-25 12:04:41 -04:00
e82d20bfd7 Merge pull request 'added surface type to construction names' (#36) from bug_in_construction_importers into main
Reviewed-on: https://nextgenerations-cities.encs.concordia.ca/gitea/CERC/hub/pulls/36
2023-07-25 12:03:42 -04:00
a3d4390a19 added surface type to construction names 2023-07-25 12:02:20 -04:00
c5c298d708 Update hub/version.py 2023-07-25 09:31:24 -04:00
1ae07cc14f Merge remote-tracking branch 'origin/main' 2023-07-25 09:29:46 -04:00
37c09df932 IDF export will not longer blindly assign the Montreal as weather file 2023-07-25 09:29:39 -04:00
92f0c81109 Update hub/version.py 2023-07-24 12:33:55 -04:00
a8c961f7bc Correct trimesh dependency 2023-07-24 12:33:24 -04:00
2c7fc66423 Update hub/version.py 2023-07-21 16:12:37 -04:00
32 changed files with 336 additions and 308 deletions

3
cerc_hub.egg-info/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
# Except this file
*
!.gitignore

View File

@ -34,7 +34,7 @@ class Archetype:
Get name Get name
:return: string :return: string
""" """
return f'{self._name}_lod{self._lod}' return self._name
@property @property
def systems(self) -> List[System]: def systems(self) -> List[System]:

View File

@ -55,7 +55,7 @@ class System:
Get name Get name
:return: string :return: string
""" """
return f'{self._name}_lod{self._lod}' return self._name
@property @property
def demand_types(self): def demand_types(self):

View File

@ -385,6 +385,42 @@ class Building(CityObject):
""" """
self._domestic_hot_water_heat_demand = value self._domestic_hot_water_heat_demand = value
@property
def lighting_peak_load(self) -> Union[None, dict]:
"""
Get lighting peak load in W
:return: dict{[float]}
"""
results = {}
peak_lighting = 0
for thermal_zone in self.thermal_zones:
lighting = thermal_zone.lighting
for schedule in lighting.schedules:
peak = max(schedule.values) * lighting.density * thermal_zone.total_floor_area
if peak > peak_lighting:
peak_lighting = peak
results[cte.MONTH] = [peak for _ in range(0, 12)]
results[cte.YEAR] = [peak]
return results
@property
def appliances_peak_load(self) -> Union[None, dict]:
"""
Get appliances peak load in W
:return: dict{[float]}
"""
results = {}
peak_appliances = 0
for thermal_zone in self.thermal_zones:
appliances = thermal_zone.appliances
for schedule in appliances.schedules:
peak = max(schedule.values) * appliances.density * thermal_zone.total_floor_area
if peak > peak_appliances:
peak_appliances = peak
results[cte.MONTH] = [peak for _ in range(0, 12)]
results[cte.YEAR] = [peak]
return results
@property @property
def heating_peak_load(self) -> Union[None, dict]: def heating_peak_load(self) -> Union[None, dict]:
""" """

View File

@ -7,10 +7,13 @@ Project Coder Pilar Monsalvete Alvarez de uribarri pilar.monsalvete@concordia.ca
from pathlib import Path from pathlib import Path
import requests
from hub.exports.building_energy.energy_ade import EnergyAde from hub.exports.building_energy.energy_ade import EnergyAde
from hub.exports.building_energy.idf import Idf from hub.exports.building_energy.idf import Idf
from hub.exports.building_energy.insel.insel_monthly_energy_balance import InselMonthlyEnergyBalance from hub.exports.building_energy.insel.insel_monthly_energy_balance import InselMonthlyEnergyBalance
from hub.helpers.utils import validate_import_export_type from hub.helpers.utils import validate_import_export_type
from hub.imports.weather.helpers.weather import Weather as wh
class EnergyBuildingsExportsFactory: class EnergyBuildingsExportsFactory:
@ -49,8 +52,11 @@ class EnergyBuildingsExportsFactory:
:return: None :return: None
""" """
idf_data_path = (Path(__file__).parent / './building_energy/idf_files/').resolve() idf_data_path = (Path(__file__).parent / './building_energy/idf_files/').resolve()
# todo: create a get epw file function based on the city url = wh().epw_file(self._city.region_code)
weather_path = (Path(__file__).parent / '../data/weather/epw/CAN_PQ_Montreal.Intl.AP.716270_CWEC.epw').resolve() weather_path = (Path(__file__).parent.parent / f'data/weather/epw/{url.rsplit("/", 1)[1]}').resolve()
if not weather_path.exists():
with open(weather_path, 'wb') as epw_file:
epw_file.write(requests.get(url, allow_redirects=True).content)
return Idf(self._city, self._path, (idf_data_path / 'Minimal.idf'), (idf_data_path / 'Energy+.idd'), weather_path, return Idf(self._city, self._path, (idf_data_path / 'Minimal.idf'), (idf_data_path / 'Energy+.idd'), weather_path,
target_buildings=self._target_buildings) target_buildings=self._target_buildings)

View File

@ -0,0 +1,28 @@
"""
Dictionaries module for montreal custom fuel to hub fuel
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
"""
import hub.helpers.constants as cte
class MontrealCustomFuelToHubFuel:
"""
Montreal custom fuel to hub fuel class
"""
def __init__(self):
self._dictionary = {
'gas': cte.GAS,
'electricity': cte.ELECTRICITY,
'renewable': cte.RENEWABLE
}
@property
def dictionary(self) -> dict:
"""
Get the dictionary
:return: {}
"""
return self._dictionary

View File

@ -6,6 +6,7 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
from hub.helpers.data.hft_function_to_hub_function import HftFunctionToHubFunction from hub.helpers.data.hft_function_to_hub_function import HftFunctionToHubFunction
from hub.helpers.data.montreal_custom_fuel_to_hub_fuel import MontrealCustomFuelToHubFuel
from hub.helpers.data.montreal_function_to_hub_function import MontrealFunctionToHubFunction from hub.helpers.data.montreal_function_to_hub_function import MontrealFunctionToHubFunction
from hub.helpers.data.eilat_function_to_hub_function import EilatFunctionToHubFunction from hub.helpers.data.eilat_function_to_hub_function import EilatFunctionToHubFunction
from hub.helpers.data.alkis_function_to_hub_function import AlkisFunctionToHubFunction from hub.helpers.data.alkis_function_to_hub_function import AlkisFunctionToHubFunction
@ -141,3 +142,10 @@ class Dictionaries:
Get Eilat's function to hub function, transformation dictionary Get Eilat's function to hub function, transformation dictionary
""" """
return EilatFunctionToHubFunction().dictionary return EilatFunctionToHubFunction().dictionary
@property
def montreal_custom_fuel_to_hub_fuel(self) -> dict:
"""
Get hub fuel from montreal_custom catalog fuel
"""
return MontrealCustomFuelToHubFuel().dictionary

View File

@ -13,10 +13,7 @@ class ConstructionHelper:
Construction helper Construction helper
""" """
# NREL # NREL
_nrel_standards = {
'ASHRAE Std189': 1,
'ASHRAE 90.1_2004': 2
}
_reference_city_to_nrel_climate_zone = { _reference_city_to_nrel_climate_zone = {
'Miami': 'ASHRAE_2004:1A', 'Miami': 'ASHRAE_2004:1A',
'Houston': 'ASHRAE_2004:2A', 'Houston': 'ASHRAE_2004:2A',
@ -35,17 +32,6 @@ class ConstructionHelper:
'Duluth': 'ASHRAE_2004:7A', 'Duluth': 'ASHRAE_2004:7A',
'Fairbanks': 'ASHRAE_2004:8A' 'Fairbanks': 'ASHRAE_2004:8A'
} }
nrel_window_types = [cte.WINDOW, cte.DOOR, cte.SKYLIGHT]
nrel_construction_types = {
cte.WALL: 'exterior wall',
cte.INTERIOR_WALL: 'interior wall',
cte.GROUND_WALL: 'ground wall',
cte.GROUND: 'exterior slab',
cte.ATTIC_FLOOR: 'attic floor',
cte.INTERIOR_SLAB: 'interior slab',
cte.ROOF: 'roof'
}
_reference_city_to_nrcan_climate_zone = { _reference_city_to_nrcan_climate_zone = {
'Montreal': '6', 'Montreal': '6',

View File

@ -0,0 +1,29 @@
"""
Energy systems helper
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from hub.helpers import constants as cte
class EnergySystemsHelper:
"""
EnergySystems helper
"""
_montreal_custom_fuel_to_hub_fuel = {
'gas': cte.GAS,
'electricity': cte.ELECTRICITY,
'renewable': cte.RENEWABLE
}
@staticmethod
def montreal_custom_fuel_to_hub_fuel(fuel):
"""
Get hub fuel from montreal_custom catalog fuel
:param fuel: str
:return: str
"""
return EnergySystemsHelper._montreal_custom_fuel_to_hub_fuel[fuel]

View File

@ -19,6 +19,7 @@ from hub.city_model_structure.energy_systems.generation_system import Generation
from hub.city_model_structure.energy_systems.distribution_system import DistributionSystem from hub.city_model_structure.energy_systems.distribution_system import DistributionSystem
from hub.city_model_structure.energy_systems.emission_system import EmissionSystem from hub.city_model_structure.energy_systems.emission_system import EmissionSystem
from hub.helpers.dictionaries import Dictionaries from hub.helpers.dictionaries import Dictionaries
from hub.imports.energy_systems.helpers.energy_systems_helper import EnergySystemsHelper
class MontrealCustomEnergySystemParameters: class MontrealCustomEnergySystemParameters:
@ -45,7 +46,7 @@ class MontrealCustomEnergySystemParameters:
else: else:
_generic_energy_systems = city.generic_energy_systems _generic_energy_systems = city.generic_energy_systems
for building in city.buildings: for building in city.buildings:
archetype_name = f'{building.energy_systems_archetype_name}_lod1.0' archetype_name = building.energy_systems_archetype_name
try: try:
archetype = self._search_archetypes(montreal_custom_catalog, archetype_name) archetype = self._search_archetypes(montreal_custom_catalog, archetype_name)
except KeyError: except KeyError:
@ -53,9 +54,12 @@ class MontrealCustomEnergySystemParameters:
archetype_name) archetype_name)
continue continue
_energy_systems_connection_table, _generic_energy_systems \ _energy_systems_connection_table, _generic_energy_systems = self._create_generic_systems(
= self._create_generic_systems(archetype, building, archetype,
_energy_systems_connection_table, _generic_energy_systems) building,
_energy_systems_connection_table,
_generic_energy_systems
)
city.energy_systems_connection_table = _energy_systems_connection_table city.energy_systems_connection_table = _energy_systems_connection_table
city.generic_energy_systems = _generic_energy_systems city.generic_energy_systems = _generic_energy_systems
@ -84,10 +88,11 @@ class MontrealCustomEnergySystemParameters:
energy_system.demand_types = _hub_demand_types energy_system.demand_types = _hub_demand_types
_generation_system = GenericGenerationSystem() _generation_system = GenericGenerationSystem()
archetype_generation_equipment = system.generation_system archetype_generation_equipment = system.generation_system
_type = str(system.name).split('_', maxsplit=1)[0] _type = system.name
_generation_system.type = Dictionaries().montreal_system_to_hub_energy_generation_system[ _generation_system.type = Dictionaries().montreal_system_to_hub_energy_generation_system[
_type] _type]
_generation_system.fuel_type = archetype_generation_equipment.fuel_type _fuel_type = Dictionaries().montreal_custom_fuel_to_hub_fuel[archetype_generation_equipment.fuel_type]
_generation_system.fuel_type = _fuel_type
_generation_system.source_types = archetype_generation_equipment.source_types _generation_system.source_types = archetype_generation_equipment.source_types
_generation_system.heat_efficiency = archetype_generation_equipment.heat_efficiency _generation_system.heat_efficiency = archetype_generation_equipment.heat_efficiency
_generation_system.cooling_efficiency = archetype_generation_equipment.cooling_efficiency _generation_system.cooling_efficiency = archetype_generation_equipment.cooling_efficiency

View File

@ -1,144 +0,0 @@
"""
Rhino module parses rhino files and import the geometry into the city model structure
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.capip
"""
import numpy as np
from rhino3dm import *
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
from hub.city_model_structure.building import Building
from hub.city_model_structure.building_demand.surface import Surface as HubSurface
from hub.city_model_structure.city import City
from hub.helpers.configuration_helper import ConfigurationHelper
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)
min_float = float(ConfigurationHelper().min_coordinate)
self._min_x = self._min_y = self._min_z = max_float
self._max_x = self._max_y = self._max_z = min_float
@staticmethod
def _in_perimeter(wall, corner):
res = wall.contains_point(Point(corner))
return res
@staticmethod
def _add_hole(solid_polygon, hole):
first = solid_polygon.points[0]
points = first + hole.points + solid_polygon.points
return Polygon(points)
@staticmethod
def _solid_points(coordinates) -> np.ndarray:
solid_points = np.fromstring(coordinates, dtype=float, sep=' ')
solid_points = GeometryHelper.to_points_matrix(solid_points)
result = []
found = False
for row in solid_points:
for row2 in result:
if row[0] == row2[0] and row[1] == row2[1] and row[2] == row2[2]:
found = True
if not found:
result.append(row)
return solid_points
def _corners(self, point):
if point.X < self._min_x:
self._min_x = point.X
if point.Y < self._min_y:
self._min_y = point.Y
if point.Z < self._min_z:
self._min_z = point.Z
if point.X > self._max_x:
self._max_x = point.X
if point.Y > self._max_y:
self._max_y = point.Y
if point.Z > self._max_z:
self._max_z = point.Z
def _add_face(self, face):
hub_surfaces = []
_mesh = face.GetMesh(MeshType.Default)
for i in range(0, len(_mesh.Faces)):
mesh_faces = _mesh.Faces[i]
_points = ''
faces = []
for index in mesh_faces:
if index in faces:
continue
faces.append(index)
self._corners(_mesh.Vertices[index])
_points = _points + f'{_mesh.Vertices[index].X} {_mesh.Vertices[index].Y} {_mesh.Vertices[index].Z} '
polygon_points = Rhino._solid_points(_points.strip())
hub_surfaces.append(HubSurface(Polygon(polygon_points), Polygon(polygon_points)))
return hub_surfaces
@property
def city(self) -> City:
"""
Return a city based in the rhino file
:return: City
"""
buildings = []
city_objects = [] # building and "windows"
windows = []
_prev_name = ''
for obj in self._model.Objects:
name = obj.Attributes.Id
hub_surfaces = []
if isinstance(obj.Geometry, Extrusion):
surface = obj.Geometry
hub_surfaces = hub_surfaces + self._add_face(surface)
else:
for face in obj.Geometry.Faces:
if face is None:
break
hub_surfaces = hub_surfaces + self._add_face(face)
building = Building(name, hub_surfaces, 'unknown', 'unknown', [])
city_objects.append(building)
lower_corner = (self._min_x, self._min_y, self._min_z)
upper_corner = (self._max_x, self._max_y, self._max_z)
city = City(lower_corner, upper_corner, 'EPSG:26918')
for building in city_objects:
if len(building.surfaces) <= 2:
# is not a building but a window!
for surface in building.surfaces:
# add to windows the "hole" with the normal inverted
windows.append(Polygon(surface.perimeter_polygon.inverse))
else:
buildings.append(building)
# todo: this method will be pretty inefficient
for hole in windows:
corner = hole.coordinates[0]
for building in buildings:
for surface in building.surfaces:
plane = surface.perimeter_polygon.plane
# todo: this is a hack for dompark project it should not be done this way windows should be correctly modeled
# if the distance between the wall plane and the window is less than 2m
# and the window Z coordinate it's between the wall Z, it's a window of that wall
if plane.distance_to_point(corner) <= 2:
# check if the window is in the right high.
if surface.upper_corner[2] >= corner[2] >= surface.lower_corner[2]:
if surface.holes_polygons is None:
surface.holes_polygons = []
surface.holes_polygons.append(hole)
for building in buildings:
city.add_city_object(building)
building.level_of_detail.geometry = 3
city.level_of_detail.geometry = 3
return city

View File

@ -12,7 +12,6 @@ from hub.imports.geometry.citygml import CityGml
from hub.imports.geometry.geojson import Geojson from hub.imports.geometry.geojson import Geojson
from hub.imports.geometry.gpandas import GPandas from hub.imports.geometry.gpandas import GPandas
from hub.imports.geometry.obj import Obj from hub.imports.geometry.obj import Obj
from hub.imports.geometry.rhino import Rhino
class GeometryFactory: class GeometryFactory:
@ -80,14 +79,6 @@ class GeometryFactory:
self._function_field, self._function_field,
self._function_to_hub).city self._function_to_hub).city
@property
def _rhino(self) -> City:
"""
Enrich the city by using Rhino information as data source
:return: City
"""
return Rhino(self._path).city
@property @property
def city(self) -> City: def city(self) -> City:
""" """

View File

@ -7,9 +7,9 @@ Project CoderPeter Yefi peteryefi@gmail.com
import json import json
from typing import Dict from typing import Dict
from hub.city_model_structure.city import City
from hub.persistence.repositories.application import Application from hub.persistence.repositories.application import Application
from hub.persistence.repositories.city import City as CityRepository from hub.persistence.repositories.city import City
from hub.persistence.repositories.city_object import CityObject from hub.persistence.repositories.city_object import CityObject
from hub.persistence.repositories.simulation_results import SimulationResults from hub.persistence.repositories.simulation_results import SimulationResults
from hub.persistence.repositories.user import User from hub.persistence.repositories.user import User
@ -22,7 +22,7 @@ class DBControl:
""" """
def __init__(self, db_name, app_env, dotenv_path): def __init__(self, db_name, app_env, dotenv_path):
self._city_repository = CityRepository(db_name=db_name, dotenv_path=dotenv_path, app_env=app_env) self._city = City(db_name=db_name, dotenv_path=dotenv_path, app_env=app_env)
self._application = Application(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path) self._application = Application(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path)
self._user = User(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path) self._user = User(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path)
self._city_object = CityObject(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path) self._city_object = CityObject(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path)
@ -63,7 +63,23 @@ class DBControl:
:param application_id: Application id :param application_id: Application id
:return: [City] :return: [City]
""" """
return self._city_repository.get_by_user_id_and_application_id(user_id, application_id) return self._city.get_by_user_id_and_application_id(user_id, application_id)
def building(self, name, user_id, application_id, scenario) -> CityObject:
"""
Retrieve the building from the database
:param name: Building name
:param user_id: User id
:param application_id: Application id
:param scenario: Scenario
:
"""
cities = self._city.get_by_user_id_application_id_and_scenario(user_id, application_id, scenario)
for city in cities:
result = self.building_info(name, city[0].id)
if result is not None:
return result
return None
def building_info(self, name, city_id) -> CityObject: def building_info(self, name, city_id) -> CityObject:
""" """
@ -72,51 +88,71 @@ class DBControl:
:param city_id: City ID :param city_id: City ID
:return: CityObject :return: CityObject
""" """
return self._city_object.get_by_name_and_city(name, city_id) return self._city_object.get_by_name_or_alias_and_city(name, city_id)
def results(self, user_id, application_id, cities, result_names=None) -> Dict: def buildings_info(self, request_values, city_id) -> [CityObject]:
"""
Retrieve the buildings info from the database
:param request_values: Building names
:param city_id: City ID
:return: [CityObject]
"""
buildings = []
for name in request_values['names']:
buildings.append(self.building_info(name, city_id))
return buildings
def results(self, user_id, application_id, request_values, result_names=None) -> Dict:
""" """
Retrieve the simulation results for the given cities from the database Retrieve the simulation results for the given cities from the database
:param user_id: the user id owning the results :param user_id: the user id owning the results
:param application_id: the application id owning the results :param application_id: the application id owning the results
:param cities: dictionary containing the city and building names for the results :param request_values: dictionary containing the scenario and building names to grab the results
:param result_names: if given, filter the results to the selected names :param result_names: if given, filter the results to the selected names
""" """
if result_names is None: if result_names is None:
result_names = [] result_names = []
results = {} results = {}
for city in cities['cities']: for scenario in request_values['scenarios']:
city_name = next(iter(city)) scenario_name = next(iter(scenario))
result_set = self._city_repository.get_by_user_id_application_id_and_name(user_id, application_id, city_name) result_sets = self._city.get_by_user_id_application_id_and_scenario(
if result_set is None: user_id,
application_id,
scenario_name
)
if result_sets is None:
continue continue
city_id = result_set.id for result_set in result_sets:
results[city_name] = [] city_id = result_set[0].id
for building_name in city[city_name]:
if self._city_object.get_by_name_and_city(building_name, city_id) is None:
continue
city_object_id = self._city_object.get_by_name_and_city(building_name, city_id).id
_ = self._simulation_results.get_simulation_results_by_city_id_city_object_id_and_names(
city_id,
city_object_id,
result_names)
for value in _: results[scenario_name] = []
values = json.loads(value.values) for building_name in scenario[scenario_name]:
values["building"] = building_name _building = self._city_object.get_by_name_or_alias_and_city(building_name, city_id)
results[city_name].append(values) if _building is None:
continue
city_object_id = _building.id
_ = self._simulation_results.get_simulation_results_by_city_id_city_object_id_and_names(
city_id,
city_object_id,
result_names)
for value in _:
values = json.loads(value.values)
values["building"] = building_name
results[scenario_name].append(values)
return results return results
def persist_city(self, city: City, pickle_path, application_id: int, user_id: int): def persist_city(self, city: City, pickle_path, scenario, application_id: int, user_id: int):
""" """
Creates a city into the database Creates a city into the database
:param city: City to be stored :param city: City to be stored
:param pickle_path: Path to save the pickle file :param pickle_path: Path to save the pickle file
:param scenario: Simulation scenario name
:param application_id: Application id owning this city :param application_id: Application id owning this city
:param user_id: User who create the city :param user_id: User who create the city
return identity_id return identity_id
""" """
return self._city_repository.insert(city, pickle_path, application_id, user_id) return self._city.insert(city, pickle_path, scenario, application_id, user_id)
def update_city(self, city_id, city): def update_city(self, city_id, city):
""" """
@ -124,7 +160,7 @@ class DBControl:
:param city_id: the id of the city to update :param city_id: the id of the city to update
:param city: the updated city object :param city: the updated city object
""" """
return self._city_repository.update(city_id, city) return self._city.update(city_id, city)
def persist_application(self, name: str, description: str, application_uuid: str): def persist_application(self, name: str, description: str, application_uuid: str):
""" """
@ -194,7 +230,7 @@ class DBControl:
Deletes a single city from the database Deletes a single city from the database
:param city_id: the id of the city to get :param city_id: the id of the city to get
""" """
self._city_repository.delete(city_id) self._city.delete(city_id)
def delete_results_by_name(self, name, city_id=None, city_object_id=None): def delete_results_by_name(self, name, city_id=None, city_object_id=None):
""" """

View File

@ -20,19 +20,17 @@ class City(Models):
id = Column(Integer, Sequence('city_id_seq'), primary_key=True) id = Column(Integer, Sequence('city_id_seq'), primary_key=True)
pickle_path = Column(String, nullable=False) pickle_path = Column(String, nullable=False)
name = Column(String, nullable=False) name = Column(String, nullable=False)
level_of_detail = Column(Integer, nullable=False) scenario = Column(String, nullable=False)
climate_file = Column(String, nullable=False)
application_id = Column(Integer, ForeignKey('application.id'), nullable=False) application_id = Column(Integer, ForeignKey('application.id'), nullable=False)
user_id = Column(Integer, ForeignKey('user.id'), nullable=True) user_id = Column(Integer, ForeignKey('user.id'), nullable=True)
hub_release = Column(String, nullable=False) hub_release = Column(String, nullable=False)
created = Column(DateTime, default=datetime.datetime.utcnow) created = Column(DateTime, default=datetime.datetime.utcnow)
updated = Column(DateTime, default=datetime.datetime.utcnow) updated = Column(DateTime, default=datetime.datetime.utcnow)
def __init__(self, pickle_path, name, level_of_detail, climate_file, application_id, user_id, hub_release): def __init__(self, pickle_path, name, scenario, application_id, user_id, hub_release):
self.pickle_path = str(pickle_path) self.pickle_path = str(pickle_path)
self.name = name self.name = name
self.level_of_detail = level_of_detail self.scenario = scenario
self.climate_file = climate_file
self.application_id = application_id self.application_id = application_id
self.user_id = user_id self.user_id = user_id
self.hub_release = hub_release self.hub_release = hub_release

View File

@ -33,6 +33,7 @@ class CityObject(Models):
wall_area = Column(Float, nullable=False) wall_area = Column(Float, nullable=False)
windows_area = Column(Float, nullable=False) windows_area = Column(Float, nullable=False)
roof_area = Column(Float, nullable=False) roof_area = Column(Float, nullable=False)
total_pv_area = Column(Float, nullable=False)
system_name = Column(String, nullable=False) system_name = Column(String, nullable=False)
created = Column(DateTime, default=datetime.datetime.utcnow) created = Column(DateTime, default=datetime.datetime.utcnow)
updated = Column(DateTime, default=datetime.datetime.utcnow) updated = Column(DateTime, default=datetime.datetime.utcnow)
@ -48,6 +49,7 @@ class CityObject(Models):
self.volume = building.volume self.volume = building.volume
self.area = building.floor_area self.area = building.floor_area
self.roof_area = sum(roof.solid_polygon.area for roof in building.roofs) self.roof_area = sum(roof.solid_polygon.area for roof in building.roofs)
self.total_pv_area = sum(roof.solid_polygon.area * roof.solar_collectors_area_reduction_factor for roof in building.roofs)
storeys = building.storeys_above_ground storeys = building.storeys_above_ground
if storeys is None: if storeys is None:
storeys = building.max_height / building.average_storey_height storeys = building.max_height / building.average_storey_height

View File

@ -34,11 +34,12 @@ class City(Repository):
cls._instance = super(City, cls).__new__(cls) cls._instance = super(City, cls).__new__(cls)
return cls._instance return cls._instance
def insert(self, city: CityHub, pickle_path, application_id, user_id: int): def insert(self, city: CityHub, pickle_path, scenario, application_id, user_id: int):
""" """
Inserts a city Inserts a city
:param city: The complete city instance :param city: The complete city instance
:param pickle_path: Path to the pickle :param pickle_path: Path to the pickle
:param scenario: Simulation scenario name
:param application_id: Application id owning the instance :param application_id: Application id owning the instance
:param user_id: User id owning the instance :param user_id: User id owning the instance
:return: Identity id :return: Identity id
@ -48,8 +49,7 @@ class City(Repository):
db_city = Model( db_city = Model(
pickle_path, pickle_path,
city.name, city.name,
city.level_of_detail.geometry, scenario,
'None' if city.climate_file is None else str(city.climate_file),
application_id, application_id,
user_id, user_id,
__version__) __version__)
@ -98,21 +98,19 @@ class City(Repository):
logging.error('Error while fetching city %s', err) logging.error('Error while fetching city %s', err)
raise SQLAlchemyError from err raise SQLAlchemyError from err
def get_by_user_id_application_id_and_name(self, user_id, application_id, city_name) -> Model: def get_by_user_id_application_id_and_scenario(self, user_id, application_id, scenario) -> [Model]:
""" """
Fetch city based on the user who created it Fetch city based on the user who created it
:param user_id: the user id :param user_id: the user id
:param application_id: the application id :param application_id: the application id
:param city_name: the city name :param scenario: simulation scenario name
:return: ModelCity :return: [ModelCity]
""" """
try: try:
result_set = self.session.execute(select(Model).where(Model.user_id == user_id, result_set = self.session.execute(select(Model).where(Model.user_id == user_id,
Model.application_id == application_id, Model.application_id == application_id,
Model.name == city_name Model.scenario == scenario
)).first() )).all()
if result_set is not None:
result_set = result_set[0]
return result_set return result_set
except SQLAlchemyError as err: except SQLAlchemyError as err:
logging.error('Error while fetching city by name %s', err) logging.error('Error while fetching city by name %s', err)
@ -133,3 +131,4 @@ class City(Repository):
except SQLAlchemyError as err: except SQLAlchemyError as err:
logging.error('Error while fetching city by name %s', err) logging.error('Error while fetching city by name %s', err)
raise SQLAlchemyError from err raise SQLAlchemyError from err

View File

@ -7,7 +7,7 @@ Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
import datetime import datetime
import logging import logging
from sqlalchemy import select from sqlalchemy import select, or_
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
from hub.city_model_structure.building import Building from hub.city_model_structure.building import Building
@ -39,7 +39,7 @@ class CityObject(Repository):
:param building: the city object (only building for now) to be inserted :param building: the city object (only building for now) to be inserted
return Identity id return Identity id
""" """
city_object = self.get_by_name_and_city(building.name, city_id) city_object = self.get_by_name_or_alias_and_city(building.name, city_id)
if city_object is not None: if city_object is not None:
raise SQLAlchemyError(f'A city_object named {building.name} already exists in that city') raise SQLAlchemyError(f'A city_object named {building.name} already exists in that city')
try: try:
@ -96,19 +96,30 @@ class CityObject(Repository):
logging.error('Error while deleting application %s', err) logging.error('Error while deleting application %s', err)
raise SQLAlchemyError from err raise SQLAlchemyError from err
def get_by_name_and_city(self, name, city_id) -> Model: def get_by_name_or_alias_and_city(self, name, city_id) -> Model:
""" """
Fetch a city object based on name and city id Fetch a city object based on name and city id
:param name: city object name :param name: city object name
:param city_id: a city identifier :param city_id: a city identifier
:return: [CityObject] with the provided name belonging to the city with id city_id :return: [CityObject] with the provided name or alias belonging to the city with id city_id
""" """
_city_object = None
try: try:
_city_object = self.session.execute(select(Model).where( # search by name first
Model.name == name, Model.city_id == city_id city_object = self.session.execute(select(Model).where(Model.name == name, Model.city_id == city_id)).first()
)).first() if city_object is not None:
return _city_object[0] return city_object[0]
city_objects = self.session.execute(
select(Model).where(Model.aliases.contains(name), Model.city_id == city_id)
).all()
# name not found, so search by alias instead
for city_object in city_objects:
aliases = city_object[0].aliases.replace('{', '').replace('}', '').split(',')
for alias in aliases:
if alias == name:
# force the name as the alias
city_object[0].name = name
return city_object[0]
return None
except SQLAlchemyError as err: except SQLAlchemyError as err:
logging.error('Error while fetching city object by name and city: %s', err) logging.error('Error while fetching city object by name and city: %s', err)
raise SQLAlchemyError from err raise SQLAlchemyError from err

View File

@ -1,4 +1,4 @@
""" """
Hub version number Hub version number
""" """
__version__ = '0.1.7.23' __version__ = '0.1.7.29'

View File

@ -1,6 +1,6 @@
xmltodict xmltodict
numpy numpy
trimesh[all]==3.12.0 trimesh[all]
pyproj pyproj
pandas pandas
requests requests
@ -12,7 +12,6 @@ openpyxl
networkx networkx
parseidf==1.0.0 parseidf==1.0.0
ply ply
rhino3dm==7.7.0
scipy scipy
PyYAML PyYAML
pyecore==0.12.2 pyecore==0.12.2

View File

@ -72,6 +72,7 @@ setup(
'hub.imports.construction', 'hub.imports.construction',
'hub.imports.construction.helpers', 'hub.imports.construction.helpers',
'hub.imports.energy_systems', 'hub.imports.energy_systems',
'hub.imports.energy_systems.helpers',
'hub.imports.geometry', 'hub.imports.geometry',
'hub.imports.geometry.citygml_classes', 'hub.imports.geometry.citygml_classes',
'hub.imports.geometry.helpers', 'hub.imports.geometry.helpers',

View File

@ -33,7 +33,7 @@ class TestCityMerge(TestCase):
self._executable = 'sra' self._executable = 'sra'
def test_merge(self): def test_merge(self):
file_path = Path('./tests_data/test.geojson').resolve() file_path = Path(self._example_path / 'test.geojson').resolve()
full_city = GeometryFactory('geojson', file_path, height_field='citygml_me').city full_city = GeometryFactory('geojson', file_path, height_field='citygml_me').city
self.assertEqual(17, len(full_city.buildings), 'Wrong number of buildings') self.assertEqual(17, len(full_city.buildings), 'Wrong number of buildings')
odd_city = City(full_city.lower_corner, full_city.upper_corner, full_city.srs_name) odd_city = City(full_city.lower_corner, full_city.upper_corner, full_city.srs_name)
@ -54,17 +54,17 @@ class TestCityMerge(TestCase):
def test_merge_with_radiation(self): def test_merge_with_radiation(self):
sra = distutils.spawn.find_executable('sra') sra = distutils.spawn.find_executable('sra')
file_path = Path('./tests_data/test.geojson').resolve() file_path = Path(self._example_path / 'test.geojson').resolve()
output_path = Path('./tests_outputs/')
full_city = GeometryFactory('geojson', file_path, height_field='citygml_me').city full_city = GeometryFactory('geojson', file_path, height_field='citygml_me').city
even_city = City(full_city.lower_corner, full_city.upper_corner, full_city.srs_name) even_city = City(full_city.lower_corner, full_city.upper_corner, full_city.srs_name)
for building in full_city.buildings: for building in full_city.buildings:
if int(building.name) % 2 == 0: if int(building.name) % 2 == 0:
even_city.add_city_object(copy.deepcopy(building)) even_city.add_city_object(copy.deepcopy(building))
ExportsFactory('sra', full_city, output_path).export() ExportsFactory('sra', full_city, self._output_path).export()
sra_file = str((output_path / f'{full_city.name}_sra.xml').resolve()) sra_file = str((self._output_path / f'{full_city.name}_sra.xml').resolve())
subprocess.run([sra, sra_file], stdout=subprocess.DEVNULL) subprocess.run([sra, sra_file], stdout=subprocess.DEVNULL)
ResultFactory('sra', full_city, output_path).enrich() ResultFactory('sra', full_city, self._output_path).enrich()
self.assertEqual(17, len(full_city.buildings), 'Wrong number of buildings') self.assertEqual(17, len(full_city.buildings), 'Wrong number of buildings')
merged_city = full_city.merge(even_city) merged_city = full_city.merge(even_city)

View File

@ -4,34 +4,34 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group Copyright © 2022 Concordia CERC group
Project Coder Peter Yefi peteryefi@gmail.com Project Coder Peter Yefi peteryefi@gmail.com
""" """
import distutils.spawn
import glob import glob
import json import json
import logging import logging
import os import os
import subprocess import subprocess
import unittest import unittest
from unittest import TestCase
from pathlib import Path from pathlib import Path
import sqlalchemy.exc from unittest import TestCase
from hub.imports.geometry_factory import GeometryFactory import sqlalchemy.exc
from hub.imports.construction_factory import ConstructionFactory from sqlalchemy import create_engine
from hub.imports.usage_factory import UsageFactory from sqlalchemy.exc import ProgrammingError
from hub.imports.results_factory import ResultFactory
from hub.imports.weather_factory import WeatherFactory import hub.helpers.constants as cte
from hub.imports.energy_systems_factory import EnergySystemsFactory
from hub.exports.energy_building_exports_factory import EnergyBuildingsExportsFactory from hub.exports.energy_building_exports_factory import EnergyBuildingsExportsFactory
from hub.exports.exports_factory import ExportsFactory from hub.exports.exports_factory import ExportsFactory
from hub.helpers.data.montreal_function_to_hub_function import MontrealFunctionToHubFunction
from hub.imports.construction_factory import ConstructionFactory
from hub.imports.energy_systems_factory import EnergySystemsFactory
from hub.imports.geometry_factory import GeometryFactory
from hub.imports.results_factory import ResultFactory
from hub.imports.usage_factory import UsageFactory
from hub.imports.weather_factory import WeatherFactory
from hub.persistence.db_control import DBControl from hub.persistence.db_control import DBControl
from hub.persistence.repository import Repository
from sqlalchemy import create_engine
from hub.persistence.models import City, Application, CityObject, SimulationResults from hub.persistence.models import City, Application, CityObject, SimulationResults
from hub.persistence.models import User, UserRoles from hub.persistence.models import User, UserRoles
from hub.helpers.dictionaries import Dictionaries from hub.persistence.repository import Repository
from sqlalchemy.exc import ProgrammingError
import uuid
import hub.helpers.constants as cte
import distutils.spawn
class Control: class Control:
@ -52,7 +52,7 @@ class Control:
self._skip_reason = f'.env file missing at {dotenv_path}' self._skip_reason = f'.env file missing at {dotenv_path}'
return return
dotenv_path = str(dotenv_path) dotenv_path = str(dotenv_path)
repository = Repository(db_name='hub_unittests', app_env='TEST', dotenv_path=dotenv_path) repository = Repository(db_name='montreal_retrofit_test', app_env='TEST', dotenv_path=dotenv_path)
engine = create_engine(repository.configuration.connection_string) engine = create_engine(repository.configuration.connection_string)
try: try:
# delete test database if it exists # delete test database if it exists
@ -71,11 +71,16 @@ class Control:
CityObject.__table__.create(bind=repository.engine, checkfirst=True) CityObject.__table__.create(bind=repository.engine, checkfirst=True)
SimulationResults.__table__.create(bind=repository.engine, checkfirst=True) SimulationResults.__table__.create(bind=repository.engine, checkfirst=True)
city_file = "tests_data/FZK_Haus_LoD_2.gml" city_file = Path('tests_data/test.geojson').resolve()
output_path = Path('tests_outputs/').resolve() output_path = Path('tests_outputs/').resolve()
self._city = GeometryFactory('citygml', self._city = GeometryFactory('geojson',
city_file, city_file,
function_to_hub=Dictionaries().alkis_function_to_hub_function).city height_field='citygml_me',
year_of_construction_field='ANNEE_CONS',
aliases_field=['ID_UEV', 'CIVIQUE_DE', 'NOM_RUE'],
function_field='CODE_UTILI',
function_to_hub=MontrealFunctionToHubFunction().dictionary).city
ConstructionFactory('nrcan', self._city).enrich() ConstructionFactory('nrcan', self._city).enrich()
UsageFactory('nrcan', self._city).enrich() UsageFactory('nrcan', self._city).enrich()
WeatherFactory('epw', self._city).enrich() WeatherFactory('epw', self._city).enrich()
@ -84,7 +89,6 @@ class Control:
subprocess.run([self.sra, sra_file], stdout=subprocess.DEVNULL) subprocess.run([self.sra, sra_file], stdout=subprocess.DEVNULL)
ResultFactory('sra', self._city, output_path).enrich() ResultFactory('sra', self._city, output_path).enrich()
for building in self._city.buildings: for building in self._city.buildings:
building.energy_systems_archetype_name = 'system 1 gas pv' building.energy_systems_archetype_name = 'system 1 gas pv'
EnergySystemsFactory('montreal_custom', self._city).enrich() EnergySystemsFactory('montreal_custom', self._city).enrich()
@ -99,9 +103,17 @@ class Control:
app_env='TEST', app_env='TEST',
dotenv_path=dotenv_path) dotenv_path=dotenv_path)
self._application_uuid = str(uuid.uuid4()) self._application_uuid = '60b7fc1b-f389-4254-9ffd-22a4cf32c7a3'
self._application_id = self._database.persist_application('test', 'test application', self.application_uuid) self._application_id = 1
self._user_id = self._database.create_user('Admin', self._application_id, 'Admin@123', UserRoles.Admin) self._user_id = 1
self._application_id = self._database.persist_application(
'City_layers',
'City layers test user',
self.application_uuid
)
self._user_id = self._database.create_user('city_layers', self._application_id, 'city_layers', UserRoles.Admin)
self._pickle_path = 'tests_data/pickle_path.bz2' self._pickle_path = 'tests_data/pickle_path.bz2'
@property @property
@ -167,6 +179,7 @@ TestDBFactory
city_id = control.database.persist_city( city_id = control.database.persist_city(
control.city, control.city,
control.pickle_path, control.pickle_path,
control.city.name,
control.application_id, control.application_id,
control.user_id) control.user_id)
control.database.delete_city(city_id) control.database.delete_city(city_id)
@ -176,6 +189,7 @@ TestDBFactory
def test_get_update_city(self): def test_get_update_city(self):
city_id = control.database.persist_city(control.city, city_id = control.database.persist_city(control.city,
control.pickle_path, control.pickle_path,
control.city.name,
control.application_id, control.application_id,
control.user_id) control.user_id)
control.city.name = "Ottawa" control.city.name = "Ottawa"
@ -194,6 +208,7 @@ TestDBFactory
def test_save_results(self): def test_save_results(self):
city_id = control.database.persist_city(control.city, city_id = control.database.persist_city(control.city,
control.pickle_path, control.pickle_path,
'current status',
control.application_id, control.application_id,
control.user_id) control.user_id)
city_objects_id = [] city_objects_id = []
@ -206,6 +221,10 @@ TestDBFactory
yearly_cooling_peak_load = building.cooling_peak_load[cte.YEAR] yearly_cooling_peak_load = building.cooling_peak_load[cte.YEAR]
monthly_heating_peak_load = building.heating_peak_load[cte.MONTH] monthly_heating_peak_load = building.heating_peak_load[cte.MONTH]
yearly_heating_peak_load = building.heating_peak_load[cte.YEAR] yearly_heating_peak_load = building.heating_peak_load[cte.YEAR]
monthly_lighting_peak_load = building.lighting_peak_load[cte.MONTH]
yearly_lighting_peak_load = building.lighting_peak_load[cte.YEAR]
monthly_appliances_peak_load = building.appliances_peak_load[cte.MONTH]
yearly_appliances_peak_load = building.appliances_peak_load[cte.YEAR]
monthly_cooling_demand = building.cooling_demand[cte.MONTH][cte.INSEL_MEB] monthly_cooling_demand = building.cooling_demand[cte.MONTH][cte.INSEL_MEB]
yearly_cooling_demand = building.cooling_demand[cte.YEAR][cte.INSEL_MEB] yearly_cooling_demand = building.cooling_demand[cte.YEAR][cte.INSEL_MEB]
monthly_heating_demand = building.heating_demand[cte.MONTH][cte.INSEL_MEB] monthly_heating_demand = building.heating_demand[cte.MONTH][cte.INSEL_MEB]
@ -222,50 +241,59 @@ TestDBFactory
yearly_cooling_consumption = building.cooling_consumption[cte.YEAR] yearly_cooling_consumption = building.cooling_consumption[cte.YEAR]
monthly_domestic_hot_water_consumption = building.domestic_hot_water_consumption[cte.MONTH] monthly_domestic_hot_water_consumption = building.domestic_hot_water_consumption[cte.MONTH]
yearly_domestic_hot_water_consumption = building._domestic_hot_water_consumption[cte.YEAR] yearly_domestic_hot_water_consumption = building._domestic_hot_water_consumption[cte.YEAR]
monthly_distribution_systems_electrical_consumption = building.distribution_systems_electrical_consumption[cte.MONTH] monthly_distribution_systems_electrical_consumption = building.distribution_systems_electrical_consumption[
yearly_distribution_systems_electrical_consumption = building.distribution_systems_electrical_consumption[cte.YEAR] cte.MONTH]
yearly_distribution_systems_electrical_consumption = building.distribution_systems_electrical_consumption[
cte.YEAR]
monthly_on_site_electrical_production = building.onsite_electrical_production[cte.MONTH] monthly_on_site_electrical_production = building.onsite_electrical_production[cte.MONTH]
yearly_on_site_electrical_production = building.onsite_electrical_production[cte.YEAR] yearly_on_site_electrical_production = building.onsite_electrical_production[cte.YEAR]
results = json.dumps({cte.INSEL_MEB: [ results = json.dumps({cte.INSEL_MEB: [
{'monthly_cooling_peak_load': monthly_cooling_peak_load}, {'monthly_cooling_peak_load': monthly_cooling_peak_load},
{'yearly_cooling_peak_load': yearly_cooling_peak_load}, {'yearly_cooling_peak_load': yearly_cooling_peak_load},
{'monthly_heating_peak_load': monthly_heating_peak_load}, {'monthly_heating_peak_load': monthly_heating_peak_load},
{'yearly_heating_peak_load': yearly_heating_peak_load}, {'yearly_heating_peak_load': yearly_heating_peak_load},
{'monthly_cooling_demand': monthly_cooling_demand.tolist()}, {'monthly_lighting_peak_load': monthly_lighting_peak_load},
{'yearly_cooling_demand': yearly_cooling_demand.tolist()}, {'yearly_lighting_peak_load': yearly_lighting_peak_load},
{'monthly_heating_demand': monthly_heating_demand.tolist()}, {'monthly_appliances_peak_load': monthly_appliances_peak_load},
{'yearly_heating_demand': yearly_heating_demand.tolist()}, {'yearly_appliances_peak_load': yearly_appliances_peak_load},
{'monthly_lighting_electrical_demand': monthly_lighting_electrical_demand.tolist()}, {'monthly_cooling_demand': monthly_cooling_demand.tolist()},
{'yearly_lighting_electrical_demand': yearly_lighting_electrical_demand.tolist()}, {'yearly_cooling_demand': yearly_cooling_demand.tolist()},
{'monthly_appliances_electrical_demand': monthly_appliances_electrical_demand.tolist()}, {'monthly_heating_demand': monthly_heating_demand.tolist()},
{'yearly_appliances_electrical_demand': yearly_appliances_electrical_demand.tolist()}, {'yearly_heating_demand': yearly_heating_demand.tolist()},
{'monthly_domestic_hot_water_heat_demand': monthly_domestic_hot_water_heat_demand.tolist()}, {'monthly_lighting_electrical_demand': monthly_lighting_electrical_demand.tolist()},
{'yearly_domestic_hot_water_heat_demand': yearly_domestic_hot_water_heat_demand.tolist()}, {'yearly_lighting_electrical_demand': yearly_lighting_electrical_demand.tolist()},
{'monthly_heating_consumption': monthly_heating_consumption}, {'monthly_appliances_electrical_demand': monthly_appliances_electrical_demand.tolist()},
{'yearly_heating_consumption': yearly_heating_consumption}, {'yearly_appliances_electrical_demand': yearly_appliances_electrical_demand.tolist()},
{'monthly_cooling_consumption': monthly_cooling_consumption}, {'monthly_domestic_hot_water_heat_demand': monthly_domestic_hot_water_heat_demand.tolist()},
{'yearly_cooling_consumption': yearly_cooling_consumption}, {'yearly_domestic_hot_water_heat_demand': yearly_domestic_hot_water_heat_demand.tolist()},
{'monthly_domestic_hot_water_consumption': monthly_domestic_hot_water_consumption}, {'monthly_heating_consumption': monthly_heating_consumption},
{'yearly_domestic_hot_water_consumption': yearly_domestic_hot_water_consumption}, {'yearly_heating_consumption': yearly_heating_consumption},
{'monthly_distribution_systems_electrical_consumption': monthly_distribution_systems_electrical_consumption}, {'monthly_cooling_consumption': monthly_cooling_consumption},
{'yearly_distribution_systems_electrical_consumption': yearly_distribution_systems_electrical_consumption}, {'yearly_cooling_consumption': yearly_cooling_consumption},
{'monthly_on_site_electrical_production': monthly_on_site_electrical_production}, {'monthly_domestic_hot_water_consumption': monthly_domestic_hot_water_consumption},
{'yearly_on_site_electrical_production': yearly_on_site_electrical_production} {'yearly_domestic_hot_water_consumption': yearly_domestic_hot_water_consumption},
]}) {'monthly_distribution_systems_electrical_consumption': monthly_distribution_systems_electrical_consumption},
{'yearly_distribution_systems_electrical_consumption': yearly_distribution_systems_electrical_consumption},
{'monthly_on_site_electrical_production': monthly_on_site_electrical_production},
{'yearly_on_site_electrical_production': yearly_on_site_electrical_production}
]})
db_building_id = _building.id db_building_id = _building.id
city_objects_id.append(db_building_id) city_objects_id.append(db_building_id)
control.database.add_simulation_results( control.database.add_simulation_results(
cte.INSEL_MEB, cte.INSEL_MEB,
results, city_object_id=db_building_id) results, city_object_id=db_building_id)
self.assertEqual(1, len(city_objects_id), 'wrong number of results') self.assertEqual(17, len(city_objects_id), 'wrong number of results')
self.assertIsNotNone(city_objects_id[0], 'city_object_id is None') self.assertIsNotNone(city_objects_id[0], 'city_object_id is None')
"""
for _id in city_objects_id: for _id in city_objects_id:
control.database.delete_results_by_name('insel meb', city_object_id=_id) control.database.delete_results_by_name('insel meb', city_object_id=_id)
control.database.delete_city(city_id) control.database.delete_city(city_id)
@classmethod @classmethod
@unittest.skipIf(control.skip_test, control.skip_reason) @unittest.skipIf(control.skip_test, control.skip_reason)
def tearDownClass(cls): def tearDownClass(cls):
control.database.delete_application(control.application_uuid) control.database.delete_application(control.application_uuid)
control.database.delete_user(control.user_id) control.database.delete_user(control.user_id)
"""

View File

@ -4,6 +4,8 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group Copyright © 2022 Concordia CERC group
Project Coder Peter Yefi peteryefi@gmail.com Project Coder Peter Yefi peteryefi@gmail.com
""" """
from pathlib import Path
import pandas as pd import pandas as pd
from unittest import TestCase from unittest import TestCase
from hub.imports.geometry_factory import GeometryFactory from hub.imports.geometry_factory import GeometryFactory
@ -38,8 +40,10 @@ class TestEnergySystemsFactory(TestCase):
Test setup Test setup
:return: None :return: None
""" """
city_file = "tests_data/C40_Final.gml" self._example_path = (Path(__file__).parent / 'tests_data').resolve()
self._output_path = "tests_data/as_user_output.csv" self._output_path = (Path(__file__).parent / 'tests_outputs').resolve()
city_file = (self._example_path/"C40_Final.gml").resolve()
self._output_path = (self._output_path/"as_user_output.csv").resolve()
self._city = GeometryFactory('citygml', path=city_file).city self._city = GeometryFactory('citygml', path=city_file).city
EnergySystemsFactory('air_source_hp', self._city).enrich() EnergySystemsFactory('air_source_hp', self._city).enrich()

View File

@ -4,6 +4,7 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group Copyright © 2022 Concordia CERC group
Project Coder Peter Yefi peteryefi@gmail.com Project Coder Peter Yefi peteryefi@gmail.com
""" """
from pathlib import Path
from unittest import TestCase from unittest import TestCase
import pandas as pd import pandas as pd
@ -24,8 +25,10 @@ class TestEnergySystemsFactory(TestCase):
Test setup Test setup
:return: None :return: None
""" """
city_file = "tests_data/C40_Final.gml" self._example_path = (Path(__file__).parent / 'tests_data').resolve()
self._output_path = "tests_data/w2w_user_output.csv" self._output_path = (Path(__file__).parent / 'tests_outputs').resolve()
city_file = (self._example_path / "C40_Final.gml").resolve()
self._output_path = (self._example_path / "w2w_user_output.csv").resolve()
self._city = GeometryFactory('citygml', path=city_file).city self._city = GeometryFactory('citygml', path=city_file).city
EnergySystemsFactory('water_to_water_hp', self._city).enrich() EnergySystemsFactory('water_to_water_hp', self._city).enrich()

View File

@ -110,15 +110,6 @@ class TestGeometryFactory(TestCase):
self._check_surfaces(building) self._check_surfaces(building)
city = ConstructionFactory('nrel', city).enrich() city = ConstructionFactory('nrel', city).enrich()
def test_import_rhino(self):
"""
Test rhino import
"""
file = 'dompark.3dm'
city = self._get_city(file, 'rhino')
self.assertIsNotNone(city, 'city is none')
self.assertTrue(len(city.buildings) == 36)
def test_import_obj(self): def test_import_obj(self):
""" """
Test obj import Test obj import

View File

@ -23,9 +23,10 @@ class GreeneryInIdf(TestCase):
GreeneryInIdf TestCase 1 GreeneryInIdf TestCase 1
""" """
def test_greenery_in_idf(self): def test_greenery_in_idf(self):
city_file = "tests_data/one_building_in_kelowna.gml"
output_path = Path('tests_outputs/').resolve()
self._example_path = (Path(__file__).parent / 'tests_data').resolve()
output_path = (Path(__file__).parent / 'tests_outputs').resolve()
city_file = (self._example_path / "one_building_in_kelowna.gml").resolve()
city = GeometryFactory('citygml', path=city_file).city city = GeometryFactory('citygml', path=city_file).city
for building in city.buildings: for building in city.buildings:
building.year_of_construction = 2006 building.year_of_construction = 2006

View File

@ -4,6 +4,7 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group Copyright © 2023 Concordia CERC group
Project Coder Peter Yefi peteryefi@gmail.com Project Coder Peter Yefi peteryefi@gmail.com
""" """
from pathlib import Path
from unittest import TestCase from unittest import TestCase
from hub.imports.geometry_factory import GeometryFactory from hub.imports.geometry_factory import GeometryFactory
from hub.imports.energy_systems_factory import EnergySystemsFactory from hub.imports.energy_systems_factory import EnergySystemsFactory
@ -38,8 +39,9 @@ class TestHeatPumpResults(TestCase):
Test setup Test setup
:return: None :return: None
""" """
city_file = "tests_data/C40_Final.gml" self._example_path = (Path(__file__).parent / 'tests_data').resolve()
self._output_path = "tests_data/as_user_output.csv" self._output_path = (Path(__file__).parent / 'tests_outputs/as_user_output.csv').resolve()
city_file = (self._example_path / "C40_Final.gml").resolve()
self._city = GeometryFactory('citygml', path=city_file).city self._city = GeometryFactory('citygml', path=city_file).city
EnergySystemsFactory('air_source_hp', self._city).enrich() EnergySystemsFactory('air_source_hp', self._city).enrich()

View File

@ -69,6 +69,10 @@ class TestResultsImport(TestCase):
self.assertIsNotNone(building.cooling_demand[cte.MONTH][cte.INSEL_MEB]) self.assertIsNotNone(building.cooling_demand[cte.MONTH][cte.INSEL_MEB])
self.assertIsNotNone(building.heating_demand[cte.YEAR][cte.INSEL_MEB]) self.assertIsNotNone(building.heating_demand[cte.YEAR][cte.INSEL_MEB])
self.assertIsNotNone(building.cooling_demand[cte.YEAR][cte.INSEL_MEB]) self.assertIsNotNone(building.cooling_demand[cte.YEAR][cte.INSEL_MEB])
self.assertIsNotNone(building.lighting_peak_load[cte.MONTH])
self.assertIsNotNone(building.lighting_peak_load[cte.YEAR])
self.assertIsNotNone(building.appliances_peak_load[cte.MONTH])
self.assertIsNotNone(building.appliances_peak_load[cte.YEAR])
def test_peak_loads(self): def test_peak_loads(self):
# todo: this is not technically a import # todo: this is not technically a import

Binary file not shown.

Binary file not shown.

View File

@ -1,2 +1,3 @@
# Except this file # Except this file
*
!.gitignore !.gitignore