diff --git a/hub/LINUX_INSTALL.md b/hub/LINUX_INSTALL.md new file mode 100644 index 00000000..4de52244 --- /dev/null +++ b/hub/LINUX_INSTALL.md @@ -0,0 +1,50 @@ +# LINUX_INSTALL +## Prepare your environment +### Install Miniconda +1. Get the link for the latest version of Miniconda from https://docs.conda.io/en/latest/miniconda.html +2. Download the installer using wget + ```` + wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh + ```` +3. Make the installer executable + ```` + chmod +x ./Miniconda3-latest-Linux-x86_64.sh + ```` +4. Run the installer + ```` + ./Miniconda3-latest-Linux-x86_64.sh + ```` +5. Holder enter until you are prompted to accept the license terms. Enter yes. +6. Initialize the conda environment + ```` + conda init bash + ```` +7. Source .bashrc + ```` + source ~/.bashrc + ```` +8. Create a conda environment for the hub + ```` + conda create --name hub python=3.9.16 + ```` + +### Setup SRA +1. Get the sra binary and libshortwave.so library from Guille or Koa +2. Place the binary and the library into your directory of choice +3. Make a symlink for the binary and place it into /usr/local/bin/sra + ```` + sudo ln -s ~/sra /usr/local/bin/sra + ```` +4. Make a symlink for the library and place it into /usr/local/lib/libshortwave.so + ```` + sudo ln -s ~/libshortwave.so /usr/local/lib/libshortwave.so + ```` +### Setup INSEL +1. TBD + +### Get a Python editor +You are welcome to use the Python editor of your preference. The CERC team generally uses PyCharm to develop the hub. +The latest version of PyCharm can be downloaded from [JetBrains website](https://www.jetbrains.com/pycharm/promo/?source=google&medium=cpc&campaign=14127625109&term=pycharm&content=536947779504&gad=1&gclid=CjwKCAjw0ZiiBhBKEiwA4PT9z2AxPfy39x_RcBqlYxJ6sm_s55T9qvA_sZ8ZfkhIVX6FOD-ySbmzARoCcpQQAvD_BwE). + For setup and installation instructions, please view the "Get a Python Editor" +from the [WINDOWS_INSTALL](https://nextgenerations-cities.encs.concordia.ca/gitea/CERC/hub/src/branch/main/hub/WINDOWS_INSTALL.md) +documentation. \ No newline at end of file diff --git a/hub/WINDOWS_INSTALL.md b/hub/WINDOWS_INSTALL.md index 0eb13976..c31860a0 100644 --- a/hub/WINDOWS_INSTALL.md +++ b/hub/WINDOWS_INSTALL.md @@ -2,16 +2,16 @@ This is an installation guide for Windows, covering all the steps needed to begin developing code for the Urban Simulation Platform 'Hub'. At the end of this process you will have installed and configured all the necessary applications, -set up your own project on CERC's Gitlab and created your first python file. +set up your own project on CERC's Gitea and created your first python file. ## Prepare your environment -g To develop any new code for the Urban Simulation Platform you must have the right software applications installed and configured. The Platform is written in python and so the applications you need are: * Miniconda +* SRA Files * Python Editor -You also need to register a user account with the CERC's code repository on Gitlab and have the necessary permissions for +You also need to register a user account with the CERC's code repository on Gitea and have the necessary permissions for creating new code. For that purpose, please, contact Guillermo (guillermo.gutierrezmorote@concordia.ca) or Koa (kekoa.wells@concordia.ca) as soon as possible. @@ -47,6 +47,29 @@ _The term '...' is not recognized as the name of a cmdlet, function,..._ To solve it, type 'Set-ExecutionPolicy Unrestricted' as shown in the image. +### Setup SRA + +1. Get the SRA executable and dll files from Guille or Koa +2. Create a folder in "C:\Program Files\" called "sra" + +![create_sra](docs/img_windows_install/img_34.png) + +3. Copy shortwave_integer.exe and pthreadGC2.dll into the sra folder. + +![create_sra](docs/img_windows_install/img_35.png) + +4. Add the newly created sra folder to the Path, similar to step 2 from the Miniconda setup above. + +![create_sra](docs/img_windows_install/img_36.png) + +### Install and setup INSEL + +1. Get the INSEL installer from Guille or Koa +2. Run the installer to completion using the default installation path +3. Add the INSEL installation folder to the Path + +![create_sra](docs/img_windows_install/img_41.png) + ### Get a Python editor 1. You will need a python editor in order to import the existing Hub source code and to write your own python code. @@ -55,7 +78,7 @@ an excellent open-source python editor. 2. Run the installer, and follow the installation instructions for PyCharm, you may change a few options, but the default ones should be fine. -**NOTE:** If Pycharm asks you to create a Virtual Environment, click **Cancel**. You will do it later using Conda instead. +**NOTE:** If PyCharm asks you to create a Virtual Environment, click **Cancel**. You will do it later using Conda instead. ![creating_virtual_environment](docs/img_windows_install/img_31.png) @@ -70,14 +93,12 @@ You can find it also at **Git->Clone...** ![pycharm get from version control](docs/img_windows_install/img_6.png) -3. Select **Git** as the **Version control**. For the URL use the link to the Hub repository, as seen below. +3. Select **Git** as the **Version control**. Open the [hub repository](https://nextgenerations-cities.encs.concordia.ca/gitea/CERC/hub) +on Gitea and copy the URL from your browser to use as the URL inside PyCharm. ![pycharm get from version control screen](docs/img_windows_install/img_1.png) -(You can also copy this URL by going to the Hub repository in [Gitlab](https://rs-loy-gitlab.concordia.ca/Guille/hub.git) -and clicking on the **Copy URL** button, next to **Clone with HTTPS**) - -![gitlab get https](docs/img_windows_install/img_17.png) +![gitea get https](docs/img_windows_install/img_39.png) The Directory to store the Hub source code locally is automatically created for you. Edit this if you prefer it to be stored somewhere else. @@ -152,7 +173,7 @@ _lca_classes_,... And, click on the **Create** button. 3. Click on the **Git** button in the bottom-left corner to pop-up the window showing the Git information. See your new branch has been created under _Local_. -4. Now we need to let the CERC Gitlab repository know about this new branch. You do this by right-clicking on +4. Now we need to let the CERC Gitea repository know about this new branch. You do this by right-clicking on your branch and selecting **Push...** from the drop-down menu. 5. Then click on the **Push** button at the bottom-right of the **Push Commits** window. @@ -180,33 +201,35 @@ See the picture below. ![pycharm configuration screen](docs/img_windows_install/img_5.png) -## Set up a new project on Gitlab +## Set up a new project on Gitea +You will need an account before you can access the Gitea. Please contact Guillermo (guillermo.gutierrezmorote@concordia.ca) or +Koa (kekoa.wells@concordia.ca) to request an account. -1. Open a browser and to the [CERC Git](https://rs-loy-gitlab.concordia.ca/). Click on the blue **New project** button. +1. Open a browser and go to the [CERC Gitea](https://nextgenerations-cities.encs.concordia.ca/). Click on the **+** in the top right +and select "New Repository" or press the **+** below the Organization tab. -![git new project screen](docs/img_windows_install/img_14.png) +![git new project screen](docs/img_windows_install/img_37.png) 2. Choose the **Create blank project** option from the three options seen below. 3. Type in a name that describes your project: _hp_workflow_, _bus_system_optimization_... (remember to follow the CERC naming conventions described in the [Coding Style](PYGUIDE.md)). -Check the option **Initialize repository with a README**, and ideally, check the **Visibility Level** to be **Public**. +Ideally, uncheck the option **Make Repository Private**, and check the **Initialize Repository** Then click on the **Create project** button. -![git give a name](docs/img_windows_install/img_15.png) +![git give a name](docs/img_windows_install/img_38.png) You should then see a confirmation screen with all the information about your new project. ## Get your project into Pycharm -1. Now you can make a clone of this project, within PyCharm. First, copy the URL by clicking on the blue **Clone** button -and then click on the **Copy URL** button, next to the **Clone with HTTPS** link. +1. Now you can make a clone of this project, within PyCharm. First, go to the page of your repository on the Gitea and copy the URL. 2. Switch back to PyCharm and close the Hub project by choosing **File->Close Project**. You will then see the **Welcome To PyCharm** window again. 3. Clone a copy of your Project into PyCharm, following the steps 2-6 of the _GET THE CERC HUB SOURCE CODE_ -section above, but using the URL link that you just copied for your gitlab project. +section above, but using the URL link that you just copied for your Gitea project. 4. Select **File->Settings** to open the **Settings** window. From the panel on the left click on **Project: -> Project Structure**. @@ -242,5 +265,5 @@ city = GeometryFactory('citygml', path='myfile.gml').city 9. Always remember to push your own project changes as the last thing you do before ending your working day! First, commit your changes by clicking on the green check in the top-right corner of Pycharm. Add a comment that explains briefly your changes. -Then, pull by clicking on the blue arrow to be sure that there are no conflicts between your version (local) and the remote one (gitlab). +Then, pull by clicking on the blue arrow to be sure that there are no conflicts between your version (local) and the remote one (Gitea). Once the conflicts are solved and the merge in local is done, push the changes by clicking on the green arrow. diff --git a/hub/catalog_factories/data_models/energy_systems/archetype.py b/hub/catalog_factories/data_models/energy_systems/archetype.py index 7f43c5dc..4834b8cc 100644 --- a/hub/catalog_factories/data_models/energy_systems/archetype.py +++ b/hub/catalog_factories/data_models/energy_systems/archetype.py @@ -50,11 +50,11 @@ class Archetype: _systems = [] for _system in self.systems: _systems.append(_system.to_dictionary()) - content = {'Archetype': {'name': self.name, - 'level of detail': self.lod, - 'systems': _systems - } - } + content = { + 'Archetype': { + 'name': self.name, + 'level of detail': self.lod, + 'systems': _systems + } + } return content - - diff --git a/hub/catalog_factories/energy_systems/montreal_custom_catalog.py b/hub/catalog_factories/energy_systems/montreal_custom_catalog.py index b2df20c2..ee88b19c 100644 --- a/hub/catalog_factories/energy_systems/montreal_custom_catalog.py +++ b/hub/catalog_factories/energy_systems/montreal_custom_catalog.py @@ -30,9 +30,7 @@ class MontrealCustomCatalog(Catalog): 'demand', 'system_id')) self._lod = float(self._archetypes['catalog']['@lod']) - - self._catalog_generation_equipments, self._catalog_storage_equipments = \ - self._load_generation_and_storage_equipments() + self._catalog_generation_equipments, self._catalog_storage_equipments = self._load_generation_and_storage_equipments() self._catalog_distribution_equipments = self._load_distribution_equipments() self._catalog_emission_equipments = self._load_emission_equipments() self._catalog_systems = self._load_systems() @@ -63,6 +61,7 @@ class MontrealCustomCatalog(Catalog): electricity_efficiency = None if 'electrical_efficiency' in equipment: electricity_efficiency = float(equipment['electrical_efficiency']) + # todo: this may be optionals instead? generation_system = GenerationSystem(equipment_id, name, None, @@ -283,4 +282,4 @@ class MontrealCustomCatalog(Catalog): for entry in self._content.emission_equipments: if entry.name.lower() == name.lower(): return entry - raise IndexError(f"{name} doesn't exists in the catalog") \ No newline at end of file + raise IndexError(f"{name} doesn't exists in the catalog") diff --git a/hub/catalog_factories/energy_systems/north_america_energy_system_catalog.py b/hub/catalog_factories/energy_systems/north_america_energy_system_catalog.py index b5702215..77c4287c 100644 --- a/hub/catalog_factories/energy_systems/north_america_energy_system_catalog.py +++ b/hub/catalog_factories/energy_systems/north_america_energy_system_catalog.py @@ -56,7 +56,7 @@ class NorthAmericaEnergySystemCatalog(Catalog): boiler_maximum_heat_output = float(boiler['@maximumHeatOutput']) boiler_minimum_heat_output = float(boiler['@minimumHeatOutput']) boiler_heat_efficiency = float(boiler['@nominalEfficiency']) - + # todo: this may be optionals instead? boiler_component = GenerationSystem(boiler_id, boiler_name, boiler_model_name, @@ -405,15 +405,16 @@ class NorthAmericaEnergySystemCatalog(Catalog): for material in materials: if int(material.id) == int(material_id): _material = material - return _material - + break if _material is None: raise ValueError(f'Material with the id = [{material_id}] not found in catalog ') + return _material @staticmethod def _search_generation_equipment(generation_systems, generation_id): _generation_systems = [] - if type(generation_id) == list: + + if isinstance(generation_id, list): integer_ids = [int(item) for item in generation_id] for generation in generation_systems: if int(generation.id) in integer_ids: diff --git a/hub/city_model_structure/building.py b/hub/city_model_structure/building.py index 2ef73469..fca61641 100644 --- a/hub/city_model_structure/building.py +++ b/hub/city_model_structure/building.py @@ -70,6 +70,9 @@ class Building(CityObject): self._min_x = min(self._min_x, surface.lower_corner[0]) self._min_y = min(self._min_y, surface.lower_corner[1]) self._min_z = min(self._min_z, surface.lower_corner[2]) + self._max_x = max(self._max_x, surface.upper_corner[0]) + self._max_y = max(self._max_y, surface.upper_corner[1]) + self._max_z = max(self._max_z, surface.upper_corner[2]) surface.id = surface_id if surface.type == cte.GROUND: self._grounds.append(surface) @@ -86,7 +89,7 @@ class Building(CityObject): elif surface.type == cte.INTERIOR_SLAB: self._interior_slabs.append(surface) else: - logging.error(f'Building %s [%s] has an unexpected surface type %s.', self.name, self.aliases, surface.type) + logging.error('Building %s [%s] has an unexpected surface type %s.', self.name, self.aliases, surface.type) @property def shell(self) -> Polyhedron: @@ -681,11 +684,17 @@ class Building(CityObject): for i, value in enumerate(item): _working_hours[key][i] = max(_working_hours[key][i], saved_values[i]) - _total_hours = 0 - for key in _working_hours: - hours = sum(_working_hours[key]) - _total_hours += hours * cte.WEEK_DAYS_A_YEAR[key] - return _total_hours + working_hours = {} + values_months = [] + for month in cte.WEEK_DAYS_A_MONTH.keys(): + _total_hours_month = 0 + for key in _working_hours: + hours = sum(_working_hours[key]) + _total_hours_month += hours * cte.WEEK_DAYS_A_MONTH[month][key] + values_months.append(_total_hours_month) + working_hours[cte.MONTH] = values_months + working_hours[cte.YEAR] = sum(working_hours[cte.MONTH]) + return working_hours @property def distribution_systems_electrical_consumption(self): @@ -706,11 +715,11 @@ class Building(CityObject): if self.energy_systems is None: return self._distribution_systems_electrical_consumption for energy_system in self.energy_systems: - emission_system = energy_system.emission_system.generic_emission_system + emission_system = energy_system.emission_systems.generic_emission_system parasitic_energy_consumption = 0 if emission_system is not None: parasitic_energy_consumption = emission_system.parasitic_energy_consumption - distribution_system = energy_system.distribution_system.generic_distribution_system + distribution_system = energy_system.distribution_systems.generic_distribution_system consumption_variable_flow = distribution_system.distribution_consumption_variable_flow for demand_type in energy_system.demand_types: if demand_type.lower() == cte.HEATING.lower(): @@ -735,7 +744,7 @@ class Building(CityObject): 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 \ - * _working_hours + * _working_hours[key] * cte.WATTS_HOUR_TO_JULES return self._distribution_systems_electrical_consumption def _calculate_consumption(self, consumption_type, demand): @@ -744,7 +753,9 @@ class Building(CityObject): if self.energy_systems is None: return None for energy_system in self.energy_systems: - generation_systems = energy_system.generation_system + generation_systems = energy_system.generation_systems + print(generation_systems) + print(type(generation_systems)) for demand_type in energy_system.demand_types: if demand_type.lower() == consumption_type.lower(): if consumption_type in (cte.HEATING, cte.DOMESTIC_HOT_WATER): @@ -786,8 +797,8 @@ class Building(CityObject): if self.energy_systems is None: return self._onsite_electrical_production for energy_system in self.energy_systems: - if energy_system.generation_system.generic_generation_system.type == cte.PHOTOVOLTAIC: - _efficiency = energy_system.generation_system.generic_generation_system.electricity_efficiency + if energy_system.generation_systems.generic_generation_system.type == cte.PHOTOVOLTAIC: + _efficiency = energy_system.generation_systems.generic_generation_system.electricity_efficiency self._onsite_electrical_production = {} for _key in self.roofs[0].global_irradiance.keys(): _results = [0 for _ in range(0, len(self.roofs[0].global_irradiance[_key]))] diff --git a/hub/city_model_structure/building_demand/layer.py b/hub/city_model_structure/building_demand/layer.py index 3075f0bc..0becf6af 100644 --- a/hub/city_model_structure/building_demand/layer.py +++ b/hub/city_model_structure/building_demand/layer.py @@ -59,6 +59,7 @@ class Layer: Get material name :return: str """ + # todo: this should be named material_name instead return self._name @name.setter @@ -67,6 +68,7 @@ class Layer: Set material name :param value: string """ + # todo: this should be named material_name instead self._name = str(value) @property diff --git a/hub/city_model_structure/building_demand/surface.py b/hub/city_model_structure/building_demand/surface.py index 7fbef20d..9f85efb6 100644 --- a/hub/city_model_structure/building_demand/surface.py +++ b/hub/city_model_structure/building_demand/surface.py @@ -154,7 +154,6 @@ class Surface: if self._inclination is None: self._inclination = np.arccos(self.perimeter_polygon.normal[2]) return self._inclination - @property def type(self): """ diff --git a/hub/city_model_structure/building_demand/thermal_zone.py b/hub/city_model_structure/building_demand/thermal_zone.py index 386e8c4b..6ea08324 100644 --- a/hub/city_model_structure/building_demand/thermal_zone.py +++ b/hub/city_model_structure/building_demand/thermal_zone.py @@ -578,7 +578,7 @@ class ThermalZone: for i_type, _ in enumerate(_types_reference): _schedules = [] _schedule_type = _types_reference[i_type][1] - for i_schedule, schedule_value in enumerate(_schedule_type): + for _, schedule_value in enumerate(_schedule_type): schedule = Schedule() schedule.type = schedule_value.type schedule.day_types = schedule_value.day_types diff --git a/hub/city_model_structure/city.py b/hub/city_model_structure/city.py index 567b1937..97000fbb 100644 --- a/hub/city_model_structure/city.py +++ b/hub/city_model_structure/city.py @@ -14,6 +14,7 @@ import math import pickle import sys import pathlib +import os from pathlib import Path from typing import List, Union @@ -299,6 +300,20 @@ class City: with open(city_filename, 'rb') as file: return pickle.load(file) + @staticmethod + def load_compressed(compressed_city_filename, destination_filename) -> City: + """ + Load a city from compressed_city_filename + :param compressed_city_filename: Compressed pickle as source + :param destination_filename: Pickle file as destination + :return: City + """ + with open(str(compressed_city_filename), 'rb') as source, open(str(destination_filename), 'wb') as destination: + destination.write(bz2.decompress(source.read())) + loaded_city = City.load(destination_filename) + os.unlink(destination_filename) + return loaded_city + def save(self, city_filename): """ Save a city into the given filename diff --git a/hub/city_model_structure/energy_systems/electrical_storage_system.py b/hub/city_model_structure/energy_systems/electrical_storage_system.py index 54bf587c..080f86c7 100644 --- a/hub/city_model_structure/energy_systems/electrical_storage_system.py +++ b/hub/city_model_structure/energy_systems/electrical_storage_system.py @@ -13,6 +13,9 @@ from hub.city_model_structure.energy_systems.generic_storage_system import Gener class ElectricalStorageSystem: + """ + Electrical Storage system class + """ def __init__(self): self._model_name = None self._manufacturer = None @@ -150,6 +153,3 @@ class ElectricalStorageSystem: :return: float """ self._self_discharge_rate = value - - - diff --git a/hub/city_model_structure/energy_systems/energy_system.py b/hub/city_model_structure/energy_systems/energy_system.py index f4a9ea96..01d683ba 100644 --- a/hub/city_model_structure/energy_systems/energy_system.py +++ b/hub/city_model_structure/energy_systems/energy_system.py @@ -23,12 +23,12 @@ class EnergySystem: def __init__(self): self._name = None self._demand_types = None - self._generation_system = None - self._distribution_system = None - self._emission_system = None + self._generation_systems = None + self._distribution_systems = None + self._emission_systems = None self._connected_city_objects = None self._control_system = None - self._energy_storage_system = None + self._energy_storage_systems = None @property def name(self): @@ -63,52 +63,52 @@ class EnergySystem: self._demand_types = value @property - def generation_system(self) -> List[GenerationSystem]: + def generation_systems(self) -> List[GenerationSystem]: """ Get generation systems :return: GenerationSystem """ - return self._generation_system + return self._generation_systems - @generation_system.setter - def generation_system(self, value): + @generation_systems.setter + def generation_systems(self, value): """ Set generation system :param value: GenerationSystem """ - self._generation_system = value + self._generation_systems = value @property - def distribution_system(self) -> Union[None, DistributionSystem]: + def distribution_systems(self) -> Union[None, List[DistributionSystem]]: """ Get distribution system :return: DistributionSystem """ - return self._distribution_system + return self._distribution_systems - @distribution_system.setter - def distribution_system(self, value): + @distribution_systems.setter + def distribution_systems(self, value): """ Set distribution system :param value: DistributionSystem """ - self._distribution_system = value + self._distribution_systems = value @property - def emission_system(self) -> Union[None, EmissionSystem]: + def emission_systems(self) -> Union[None, List[EmissionSystem]]: """ Get emission system :return: EmissionSystem """ - return self._emission_system + return self._emission_systems - @emission_system.setter - def emission_system(self, value): + @emission_systems.setter + def emission_systems(self, value): """ Set emission system :param value: EmissionSystem """ - self._emission_system = value + self._emission_systems = value @property def connected_city_objects(self) -> Union[None, List[CityObject]]: @@ -143,17 +143,17 @@ class EnergySystem: self._control_system = value @property - def energy_storage_system(self) -> Union[None, List[ThermalStorageSystem], List[ElectricalStorageSystem]]: + def energy_storage_systems(self) -> Union[None, List[ThermalStorageSystem], List[ElectricalStorageSystem]]: """ Get energy storage systems :return: [EnergyStorageSystem] """ - return self._energy_storage_system + return self._energy_storage_systems - @energy_storage_system.setter - def energy_storage_system(self, value): + @energy_storage_systems.setter + def energy_storage_systems(self, value): """ Set storage system :param value: [EnergyStorageSystem] """ - self._energy_storage_system = value + self._energy_storage_systems = value diff --git a/hub/city_model_structure/energy_systems/generic_energy_system.py b/hub/city_model_structure/energy_systems/generic_energy_system.py index fddd4368..83661fb8 100644 --- a/hub/city_model_structure/energy_systems/generic_energy_system.py +++ b/hub/city_model_structure/energy_systems/generic_energy_system.py @@ -59,15 +59,15 @@ class GenericEnergySystem: self._demand_types = value @property - def generation_system(self) -> List[GenericGenerationSystem]: + def generation_systems(self) -> List[GenericGenerationSystem]: """ Get generation system :return: GenerationSystem """ return self._generation_system - @generation_system.setter - def generation_system(self, value): + @generation_systems.setter + def generation_systems(self, value): """ Set generation system :return: GenerationSystem @@ -75,15 +75,15 @@ class GenericEnergySystem: self._generation_system = value @property - def distribution_system(self) -> Union[None, GenericDistributionSystem]: + def distribution_systems(self) -> Union[None, List[GenericDistributionSystem]]: """ Get distribution system :return: DistributionSystem """ return self._distribution_system - @distribution_system.setter - def distribution_system(self, value): + @distribution_systems.setter + def distribution_systems(self, value): """ Set distribution system :param value: DistributionSystem @@ -91,15 +91,15 @@ class GenericEnergySystem: self._distribution_system = value @property - def emission_system(self) -> Union[None, GenericEmissionSystem]: + def emission_systems(self) -> Union[None, List[GenericEmissionSystem]]: """ Get emission system :return: EmissionSystem """ return self._emission_system - @emission_system.setter - def emission_system(self, value): + @emission_systems.setter + def emission_systems(self, value): """ Set emission system :param value: EmissionSystem @@ -107,15 +107,15 @@ class GenericEnergySystem: self._emission_system = value @property - def energy_storage_system(self) -> Union[None, GenericStorageSystem]: + def energy_storage_systems(self) -> Union[None, List[GenericStorageSystem]]: """ Get storage system :return: EnergyStorageSystem """ return self._energy_storage_system - @energy_storage_system.setter - def energy_storage_system(self, value): + @energy_storage_systems.setter + def energy_storage_systems(self, value): """ Set storage system :return: EnergyStorageSystem diff --git a/hub/city_model_structure/energy_systems/generic_storage_system.py b/hub/city_model_structure/energy_systems/generic_storage_system.py index 2b7e0bab..3cd46ca9 100644 --- a/hub/city_model_structure/energy_systems/generic_storage_system.py +++ b/hub/city_model_structure/energy_systems/generic_storage_system.py @@ -10,6 +10,9 @@ from __future__ import annotations class GenericStorageSystem: + """ + Generic storage System class + """ def __init__(self): self._storage_type = None self._nominal_capacity = None @@ -62,4 +65,3 @@ class GenericStorageSystem: :return: float """ self._losses_ratio = value - diff --git a/hub/city_model_structure/energy_systems/performance_curve.py b/hub/city_model_structure/energy_systems/performance_curve.py index 4aaaef1f..e7c72287 100644 --- a/hub/city_model_structure/energy_systems/performance_curve.py +++ b/hub/city_model_structure/energy_systems/performance_curve.py @@ -101,5 +101,3 @@ class PerformanceCurves: :return: [coefficients] """ self._coefficients = value - - diff --git a/hub/docs/img_windows_install/img_34.png b/hub/docs/img_windows_install/img_34.png new file mode 100644 index 00000000..a8d8a99d Binary files /dev/null and b/hub/docs/img_windows_install/img_34.png differ diff --git a/hub/docs/img_windows_install/img_35.png b/hub/docs/img_windows_install/img_35.png new file mode 100644 index 00000000..067b226e Binary files /dev/null and b/hub/docs/img_windows_install/img_35.png differ diff --git a/hub/docs/img_windows_install/img_36.png b/hub/docs/img_windows_install/img_36.png new file mode 100644 index 00000000..975eaf9b Binary files /dev/null and b/hub/docs/img_windows_install/img_36.png differ diff --git a/hub/docs/img_windows_install/img_37.png b/hub/docs/img_windows_install/img_37.png new file mode 100644 index 00000000..cb0679c0 Binary files /dev/null and b/hub/docs/img_windows_install/img_37.png differ diff --git a/hub/docs/img_windows_install/img_38.png b/hub/docs/img_windows_install/img_38.png new file mode 100644 index 00000000..5ea1783a Binary files /dev/null and b/hub/docs/img_windows_install/img_38.png differ diff --git a/hub/docs/img_windows_install/img_39.png b/hub/docs/img_windows_install/img_39.png new file mode 100644 index 00000000..0463d4e6 Binary files /dev/null and b/hub/docs/img_windows_install/img_39.png differ diff --git a/hub/docs/img_windows_install/img_40.png b/hub/docs/img_windows_install/img_40.png new file mode 100644 index 00000000..d01ff5b7 Binary files /dev/null and b/hub/docs/img_windows_install/img_40.png differ diff --git a/hub/docs/img_windows_install/img_41.png b/hub/docs/img_windows_install/img_41.png new file mode 100644 index 00000000..d77b8c2a Binary files /dev/null and b/hub/docs/img_windows_install/img_41.png differ diff --git a/hub/exports/formats/obj.py b/hub/exports/formats/obj.py index 2d0776d6..0392ec05 100644 --- a/hub/exports/formats/obj.py +++ b/hub/exports/formats/obj.py @@ -4,9 +4,10 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2022 Concordia CERC group Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca """ - from pathlib import Path +import numpy as np + class Obj: """ @@ -17,41 +18,79 @@ class Obj: self._path = path self._export() - def _to_vertex(self, coordinate): + def _ground(self, coordinate): x = coordinate[0] - self._city.lower_corner[0] y = coordinate[1] - self._city.lower_corner[1] z = coordinate[2] - self._city.lower_corner[2] - return f'v {x} {y} {z}\n' + return x, y, z + + def _to_vertex(self, coordinate): + x, y, z = self._ground(coordinate) + return f'v {x} {z} {y}\n' + + def _to_texture_vertex(self, coordinate): + u, v, _ = self._ground(coordinate) + return f'vt {u} {v}\n' + + def _to_normal_vertex(self, coordinates): + ground_vertex = [] + for coordinate in coordinates: + x, y, z = self._ground(coordinate) + ground_vertex.append(np.array([x, y, z])) + # recalculate the normal to get grounded values + edge_1 = ground_vertex[1] - ground_vertex[0] + edge_2 = ground_vertex[2] - ground_vertex[0] + normal = np.cross(edge_1, edge_2) + normal = normal / np.linalg.norm(normal) + return f'vn {normal[0]} {normal[1]} {normal[2]}\n' def _export(self): if self._city.name is None: self._city.name = 'unknown_city' - file_name = self._city.name + '.obj' - file_path = (Path(self._path).resolve() / file_name).resolve() + obj_name = f'{self._city.name}.obj' + mtl_name = f'{self._city.name}.mtl' + obj_file_path = (Path(self._path).resolve() / obj_name).resolve() + mtl_file_path = (Path(self._path).resolve() / mtl_name).resolve() + with open(mtl_file_path, 'w', encoding='utf-8') as mtl: + mtl.write("newmtl cerc_base_material\n") + mtl.write("Ka 1.0 1.0 1.0 # Ambient color (white)\n") + mtl.write("Kd 0.3 0.8 0.3 # Diffuse color (greenish)\n") + mtl.write("Ks 1.0 1.0 1.0 # Specular color (white)\n") + mtl.write("Ns 400.0 # Specular exponent (defines shininess)\n") vertices = {} - with open(file_path, 'w', encoding='utf-8') as obj: + faces = [] + vertex_index = 0 + normal_index = 0 + with open(obj_file_path, 'w', encoding='utf-8') as obj: obj.write("# cerc-hub export\n") - vertex_index = 0 - faces = [] + obj.write(f'mtllib {mtl_name}') + for building in self._city.buildings: obj.write(f'# building {building.name}\n') obj.write(f'g {building.name}\n') obj.write('s off\n') for surface in building.surfaces: obj.write(f'# surface {surface.name}\n') - face = 'f ' + face = [] + normal = self._to_normal_vertex(surface.perimeter_polygon.coordinates) + normal_index += 1 + textures = [] for coordinate in surface.perimeter_polygon.coordinates: vertex = self._to_vertex(coordinate) + if vertex not in vertices: vertex_index += 1 vertices[vertex] = vertex_index current = vertex_index obj.write(vertex) + textures.append(self._to_texture_vertex(coordinate)) # only append if non-existing else: current = vertices[vertex] - face = f'{face} {current}' + face.insert(0, f'{current}/{current}/{normal_index}') # insert counterclockwise + obj.writelines(normal) # add the normal + obj.writelines(textures) # add the texture vertex - faces.append(f'{face} {face.split(" ")[1]}\n') + faces.append(f"f {' '.join(face)}\n") obj.writelines(faces) faces = [] diff --git a/hub/helpers/constants.py b/hub/helpers/constants.py index 1fc51890..0f65aa59 100644 --- a/hub/helpers/constants.py +++ b/hub/helpers/constants.py @@ -49,36 +49,140 @@ WEEK_DAYS = 'Weekdays' WEEK_ENDS = 'Weekends' ALL_DAYS = 'Alldays' -WEEK_DAYS_A_MONTH = {'monday': [5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 5], - 'tuesday': [5, 4, 4, 4, 5, 4, 5, 4, 4, 5, 4, 4], - 'wednesday': [5, 4, 4, 4, 5, 4, 4, 5, 4, 5, 4, 4], - 'thursday': [4, 4, 5, 4, 5, 4, 4, 5, 4, 4, 5, 4], - 'friday': [4, 4, 5, 4, 4, 5, 4, 5, 4, 4, 5, 4], - 'saturday': [4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5], - 'sunday': [4, 4, 4, 5, 4, 4, 5, 4, 5, 4, 4, 5], - 'holiday': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]} +JANUARY = 'January' +FEBRUARY = 'February' +MARCH = 'March' +APRIL = 'April' +MAY = 'May' +JUNE = 'June' +JULY = 'July' +AUGUST = 'August' +SEPTEMBER = 'September' +OCTOBER = 'October' +NOVEMBER = 'November' +DECEMBER = 'December' -WEEK_DAYS_A_YEAR = {'monday': 51, - 'tuesday': 50, - 'wednesday': 50, - 'thursday': 50, - 'friday': 50, - 'saturday': 52, - 'sunday': 52, - 'holiday': 10} +MONTHS = [JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER] -DAYS_A_MONTH = {'January': 31, - 'February': 28, - 'March': 31, - 'April': 30, - 'May': 31, - 'June': 30, - 'July': 31, - 'August': 31, - 'September': 30, - 'October': 31, - 'November': 30, - 'December': 31} +WEEK_DAYS_A_MONTH = {JANUARY: {MONDAY: 5, + TUESDAY: 5, + WEDNESDAY: 5, + THURSDAY: 4, + FRIDAY: 4, + SATURDAY: 4, + SUNDAY: 4, + HOLIDAY: 0}, + FEBRUARY: {MONDAY: 4, + TUESDAY: 4, + WEDNESDAY: 4, + THURSDAY: 4, + FRIDAY: 4, + SATURDAY: 4, + SUNDAY: 4, + HOLIDAY: 0}, + MARCH: {MONDAY: 4, + TUESDAY: 4, + WEDNESDAY: 4, + THURSDAY: 5, + FRIDAY: 5, + SATURDAY: 5, + SUNDAY: 4, + HOLIDAY: 0}, + APRIL: {MONDAY: 5, + TUESDAY: 4, + WEDNESDAY: 4, + THURSDAY: 4, + FRIDAY: 4, + SATURDAY: 4, + SUNDAY: 5, + HOLIDAY: 0}, + MAY: {MONDAY: 4, + TUESDAY: 5, + WEDNESDAY: 5, + THURSDAY: 5, + FRIDAY: 4, + SATURDAY: 4, + SUNDAY: 4, + HOLIDAY: 0}, + JUNE: {MONDAY: 4, + TUESDAY: 4, + WEDNESDAY: 4, + THURSDAY: 4, + FRIDAY: 5, + SATURDAY: 5, + SUNDAY: 4, + HOLIDAY: 0}, + JULY: {MONDAY: 5, + TUESDAY: 5, + WEDNESDAY: 4, + THURSDAY: 4, + FRIDAY: 4, + SATURDAY: 4, + SUNDAY: 5, + HOLIDAY: 0}, + AUGUST: {MONDAY: 4, + TUESDAY: 4, + WEDNESDAY: 5, + THURSDAY: 5, + FRIDAY: 5, + SATURDAY: 4, + SUNDAY: 4, + HOLIDAY: 0}, + SEPTEMBER: {MONDAY: 4, + TUESDAY: 4, + WEDNESDAY: 4, + THURSDAY: 4, + FRIDAY: 4, + SATURDAY: 5, + SUNDAY: 5, + HOLIDAY: 0}, + OCTOBER: {MONDAY: 5, + TUESDAY: 5, + WEDNESDAY: 5, + THURSDAY: 4, + FRIDAY: 4, + SATURDAY: 4, + SUNDAY: 4, + HOLIDAY: 0}, + NOVEMBER: {MONDAY: 4, + TUESDAY: 4, + WEDNESDAY: 4, + THURSDAY: 5, + FRIDAY: 5, + SATURDAY: 4, + SUNDAY: 4, + HOLIDAY: 0}, + DECEMBER: {MONDAY: 5, + TUESDAY: 4, + WEDNESDAY: 4, + THURSDAY: 4, + FRIDAY: 4, + SATURDAY: 5, + SUNDAY: 5, + HOLIDAY: 0}, + } + +WEEK_DAYS_A_YEAR = {MONDAY: 51, + TUESDAY: 50, + WEDNESDAY: 50, + THURSDAY: 50, + FRIDAY: 50, + SATURDAY: 52, + SUNDAY: 52, + HOLIDAY: 10} + +DAYS_A_MONTH = {JANUARY: 31, + FEBRUARY: 28, + MARCH: 31, + APRIL: 30, + MAY: 31, + JUNE: 30, + JULY: 31, + AUGUST: 31, + SEPTEMBER: 30, + OCTOBER: 31, + NOVEMBER: 30, + DECEMBER: 31} # data types ANY_NUMBER = 'any_number' diff --git a/hub/helpers/data/hub_function_to_eilat_construction_function.py b/hub/helpers/data/hub_function_to_eilat_construction_function.py index 2e8cebc6..e978ac32 100644 --- a/hub/helpers/data/hub_function_to_eilat_construction_function.py +++ b/hub/helpers/data/hub_function_to_eilat_construction_function.py @@ -16,7 +16,9 @@ class HubFunctionToEilatConstructionFunction: self._dictionary = { cte.RESIDENTIAL: 'Residential_building', cte.HOTEL: 'Residential_building', - cte.DORMITORY: 'Residential_building' + cte.DORMITORY: 'Residential_building', + cte.DATACENTER: 'n/a', + cte.FARM: 'n/a' } @property diff --git a/hub/helpers/data/hub_function_to_montreal_custom_costs_function.py b/hub/helpers/data/hub_function_to_montreal_custom_costs_function.py index 06b2e16b..6c530aad 100644 --- a/hub/helpers/data/hub_function_to_montreal_custom_costs_function.py +++ b/hub/helpers/data/hub_function_to_montreal_custom_costs_function.py @@ -73,7 +73,9 @@ class HubFunctionToMontrealCustomCostsFunction: cte.AUTOMOTIVE_FACILITY: 'non-residential', cte.PARKING_GARAGE: 'non-residential', cte.RELIGIOUS: 'non-residential', - cte.NON_HEATED: 'non-residential' + cte.NON_HEATED: 'non-residential', + cte.DATACENTER: 'n/a', + cte.FARM: 'n/a' } @property diff --git a/hub/helpers/data/hub_function_to_nrcan_construction_function.py b/hub/helpers/data/hub_function_to_nrcan_construction_function.py index 8cec3715..d8618f07 100644 --- a/hub/helpers/data/hub_function_to_nrcan_construction_function.py +++ b/hub/helpers/data/hub_function_to_nrcan_construction_function.py @@ -72,7 +72,9 @@ class HubFunctionToNrcanConstructionFunction: cte.AUTOMOTIVE_FACILITY: 'n/a', cte.PARKING_GARAGE: 'n/a', cte.RELIGIOUS: 'n/a', - cte.NON_HEATED: 'n/a' + cte.NON_HEATED: 'n/a', + cte.DATACENTER: 'n/a', + cte.FARM: 'n/a' } @property diff --git a/hub/helpers/data/hub_function_to_nrel_construction_function.py b/hub/helpers/data/hub_function_to_nrel_construction_function.py index ca4144a3..39620b7b 100644 --- a/hub/helpers/data/hub_function_to_nrel_construction_function.py +++ b/hub/helpers/data/hub_function_to_nrel_construction_function.py @@ -73,7 +73,9 @@ class HubFunctionToNrelConstructionFunction: cte.AUTOMOTIVE_FACILITY: 'n/a', cte.PARKING_GARAGE: 'n/a', cte.RELIGIOUS: 'n/a', - cte.NON_HEATED: 'n/a' + cte.NON_HEATED: 'n/a', + cte.DATACENTER: 'n/a', + cte.FARM: 'n/a' } @property diff --git a/hub/helpers/data/hub_usage_to_nrcan_usage.py b/hub/helpers/data/hub_usage_to_nrcan_usage.py index 8be15d2e..e3868a6f 100644 --- a/hub/helpers/data/hub_usage_to_nrcan_usage.py +++ b/hub/helpers/data/hub_usage_to_nrcan_usage.py @@ -76,7 +76,6 @@ class HubUsageToNrcanUsage: cte.NON_HEATED: 'n/a', cte.DATACENTER: 'n/a', cte.FARM: 'n/a' - } @property diff --git a/hub/imports/construction/eilat_physics_parameters.py b/hub/imports/construction/eilat_physics_parameters.py index c09db490..8e078d5a 100644 --- a/hub/imports/construction/eilat_physics_parameters.py +++ b/hub/imports/construction/eilat_physics_parameters.py @@ -32,7 +32,7 @@ class EilatPhysicsParameters: city = self._city eilat_catalog = ConstructionCatalogFactory('eilat').catalog for building in city.buildings: - if building.function not in Dictionaries().hub_function_to_eilat_construction_function.keys(): + if building.function not in Dictionaries().hub_function_to_eilat_construction_function: logging.error('Building %s has an unknown building function %s', building.name, building.function) continue function = Dictionaries().hub_function_to_eilat_construction_function[building.function] diff --git a/hub/imports/construction/nrcan_physics_parameters.py b/hub/imports/construction/nrcan_physics_parameters.py index 8caede23..6d334cac 100644 --- a/hub/imports/construction/nrcan_physics_parameters.py +++ b/hub/imports/construction/nrcan_physics_parameters.py @@ -32,8 +32,8 @@ class NrcanPhysicsParameters: city = self._city nrcan_catalog = ConstructionCatalogFactory('nrcan').catalog for building in city.buildings: - if building.function not in Dictionaries().hub_function_to_nrcan_construction_function.keys(): - logging.error(f'Building %s has an unknown building function %s', building.name, building.function) + if building.function not in Dictionaries().hub_function_to_nrcan_construction_function: + logging.error('Building %s has an unknown building function %s', building.name, building.function) continue function = Dictionaries().hub_function_to_nrcan_construction_function[building.function] try: diff --git a/hub/imports/construction/nrel_physics_parameters.py b/hub/imports/construction/nrel_physics_parameters.py index 6f61102a..b3dc3af4 100644 --- a/hub/imports/construction/nrel_physics_parameters.py +++ b/hub/imports/construction/nrel_physics_parameters.py @@ -105,4 +105,4 @@ class NrelPhysicsParameters: construction.window_g_value = window_archetype.g_value construction.window_overall_u_value = window_archetype.overall_u_value _constructions.append(construction) - thermal_archetype.constructions = _constructions \ No newline at end of file + thermal_archetype.constructions = _constructions diff --git a/hub/imports/energy_systems/montreal_custom_energy_system_parameters.py b/hub/imports/energy_systems/montreal_custom_energy_system_parameters.py index e657e598..9960dab6 100644 --- a/hub/imports/energy_systems/montreal_custom_energy_system_parameters.py +++ b/hub/imports/energy_systems/montreal_custom_energy_system_parameters.py @@ -75,48 +75,48 @@ class MontrealCustomEnergySystemParameters: @staticmethod def _create_generic_systems(archetype, building, _energy_systems_connection_table, _generic_energy_systems): + building_systems = [] data = [archetype.name, building.name] _energy_systems_connection_table.loc[len(_energy_systems_connection_table)] = data + for system in archetype.systems: + energy_system = GenericEnergySystem() + _hub_demand_types = [] + for demand_type in system.demand_types: + _hub_demand_types.append(Dictionaries().montreal_demand_type_to_hub_energy_demand_type[demand_type]) + energy_system.name = system.name + energy_system.demand_types = _hub_demand_types + _generation_system = GenericGenerationSystem() + archetype_generation_equipment = system.generation_systems + _type = system.name + _generation_system.type = Dictionaries().montreal_system_to_hub_energy_generation_system[ + _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_medium + _generation_system.heat_efficiency = archetype_generation_equipment.heat_efficiency + _generation_system.cooling_efficiency = archetype_generation_equipment.cooling_efficiency + _generation_system.electricity_efficiency = archetype_generation_equipment.electricity_efficiency + _generation_system.source_temperature = archetype_generation_equipment.source_temperature + _generation_system.source_mass_flow = archetype_generation_equipment.source_mass_flow + _generation_system.storage = archetype_generation_equipment.storage + _generation_system.auxiliary_equipment = None + + energy_system.generation_systems = _generation_system + + _distribution_system = GenericDistributionSystem() + archetype_distribution_equipment = system.distribution_systems + _distribution_system.type = archetype_distribution_equipment.type + _distribution_system.supply_temperature = archetype_distribution_equipment.supply_temperature + _distribution_system.distribution_consumption_fix_flow = \ + archetype_distribution_equipment.distribution_consumption_fix_flow + _distribution_system.distribution_consumption_variable_flow = \ + archetype_distribution_equipment.distribution_consumption_variable_flow + _distribution_system.heat_losses = archetype_distribution_equipment.heat_losses + + energy_system.distribution_systems = _distribution_system + + building_systems.append(energy_system) if archetype.name not in _generic_energy_systems: - building_systems = [] - for system in archetype.systems: - energy_system = GenericEnergySystem() - _hub_demand_types = [] - for demand_type in system.demand_types: - _hub_demand_types.append(Dictionaries().montreal_demand_type_to_hub_energy_demand_type[demand_type]) - energy_system.name = system.name - energy_system.demand_types = _hub_demand_types - _generation_system = GenericGenerationSystem() - archetype_generation_equipment = system.generation_system - _type = system.name - _generation_system.type = Dictionaries().montreal_system_to_hub_energy_generation_system[ - _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_medium - _generation_system.heat_efficiency = archetype_generation_equipment.heat_efficiency - _generation_system.cooling_efficiency = archetype_generation_equipment.cooling_efficiency - _generation_system.electricity_efficiency = archetype_generation_equipment.electricity_efficiency - _generation_system.source_temperature = archetype_generation_equipment.source_temperature - _generation_system.source_mass_flow = archetype_generation_equipment.source_mass_flow - _generation_system.storage = archetype_generation_equipment.storage - _generation_system.auxiliary_equipment = None - - energy_system.generation_system = _generation_system - - _distribution_system = GenericDistributionSystem() - archetype_distribution_equipment = system.distribution_systems - _distribution_system.type = archetype_distribution_equipment.type - _distribution_system.supply_temperature = archetype_distribution_equipment.supply_temperature - _distribution_system.distribution_consumption_fix_flow = \ - archetype_distribution_equipment.distribution_consumption_fix_flow - _distribution_system.distribution_consumption_variable_flow = \ - archetype_distribution_equipment.distribution_consumption_variable_flow - _distribution_system.heat_losses = archetype_distribution_equipment.heat_losses - - energy_system.distribution_system = _distribution_system - - building_systems.append(energy_system) _generic_energy_systems[archetype.name] = building_systems return _energy_systems_connection_table, _generic_energy_systems @@ -145,11 +145,11 @@ class MontrealCustomEnergySystemParameters: copy.deepcopy(_generic_building_energy_system.emission_systems) _building_generation_system = GenerationSystem() _building_generation_system.generic_generation_system = \ - copy.deepcopy(_generic_building_energy_system.generation_system) + copy.deepcopy(_generic_building_energy_system.generation_systems) - _building_energy_equipment.generation_system = _building_generation_system - _building_energy_equipment.distribution_system = _building_distribution_system - _building_energy_equipment.emission_system = _building_emission_system + _building_energy_equipment.generation_systems = _building_generation_system + _building_energy_equipment.distribution_systems = _building_distribution_system + _building_energy_equipment.emission_systems = _building_emission_system _building_energy_systems.append(_building_energy_equipment) building.energy_systems = _building_energy_systems diff --git a/hub/imports/energy_systems/north_america_custom_energy_system_parameters.py b/hub/imports/energy_systems/north_america_custom_energy_system_parameters.py index f5360568..30ca9465 100644 --- a/hub/imports/energy_systems/north_america_custom_energy_system_parameters.py +++ b/hub/imports/energy_systems/north_america_custom_energy_system_parameters.py @@ -6,21 +6,20 @@ Project Coder Saeed Ranjbar saeed.ranjbar@concordia.ca Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca """ -import logging import copy +import logging from pandas import DataFrame from hub.catalog_factories.energy_systems_catalog_factory import EnergySystemsCatalogFactory -from hub.city_model_structure.energy_systems.generic_energy_system import GenericEnergySystem -from hub.city_model_structure.energy_systems.generic_generation_system import GenericGenerationSystem -from hub.city_model_structure.energy_systems.energy_system import EnergySystem -from hub.city_model_structure.energy_systems.generation_system import GenerationSystem from hub.city_model_structure.energy_systems.distribution_system import DistributionSystem from hub.city_model_structure.energy_systems.emission_system import EmissionSystem -from hub.helpers.dictionaries import Dictionaries -from hub.city_model_structure.energy_systems.generic_storage_system import GenericStorageSystem +from hub.city_model_structure.energy_systems.energy_system import EnergySystem +from hub.city_model_structure.energy_systems.generation_system import GenerationSystem +from hub.city_model_structure.energy_systems.generic_energy_system import GenericEnergySystem +from hub.city_model_structure.energy_systems.generic_generation_system import GenericGenerationSystem from hub.city_model_structure.energy_systems.thermal_storage_system import ThermalStorageSystem +from hub.helpers.dictionaries import Dictionaries class NorthAmericaCustomEnergySystemParameters: @@ -83,7 +82,7 @@ class NorthAmericaCustomEnergySystemParameters: energy_system = GenericEnergySystem() _hub_demand_types = [] demand_types = system.demand_types - if type(demand_types) == str: + if isinstance(demand_types, str): demand_types = [demand_types] for demand_type in demand_types: _hub_demand_types.append(Dictionaries().north_america_demand_type_to_hub_energy_demand_type[demand_type]) @@ -105,17 +104,17 @@ class NorthAmericaCustomEnergySystemParameters: _generation_system.source_mass_flow = archetype_generation_equipment.source_mass_flow _generation_system.storage = None _generation_system.auxiliary_equipment = None - _generation_system._supply_medium = archetype_generation_equipment.supply_medium - _generation_system._maximum_heat_supply_temperature = archetype_generation_equipment.maximum_heat_supply_temperature - _generation_system._minimum_heat_supply_temperature = archetype_generation_equipment.minimum_heat_supply_temperature - _generation_system._maximum_cooling_supply_temperature = archetype_generation_equipment.maximum_cooling_supply_temperature - _generation_system._minimum_cooling_supply_temperature = archetype_generation_equipment.minimum_cooling_supply_temperature - _generation_system._heat_output_curve = archetype_generation_equipment.heat_output_curve - _generation_system._heat_fuel_consumption_curve = archetype_generation_equipment.heat_fuel_consumption_curve - _generation_system._heat_efficiency_curve = archetype_generation_equipment.heat_efficiency_curve - _generation_system._cooling_output_curve = archetype_generation_equipment.cooling_output_curve - _generation_system._cooling_fuel_consumption_curve = archetype_generation_equipment.cooling_fuel_consumption_curve - _generation_system._cooling_efficiency_curve = archetype_generation_equipment.cooling_efficiency_curve + _generation_system.supply_medium = archetype_generation_equipment.supply_medium + _generation_system.maximum_heat_supply_temperature = archetype_generation_equipment.maximum_heat_supply_temperature + _generation_system.minimum_heat_supply_temperature = archetype_generation_equipment.minimum_heat_supply_temperature + _generation_system.maximum_cooling_supply_temperature = archetype_generation_equipment.maximum_cooling_supply_temperature + _generation_system.minimum_cooling_supply_temperature = archetype_generation_equipment.minimum_cooling_supply_temperature + _generation_system.heat_output_curve = archetype_generation_equipment.heat_output_curve + _generation_system.heat_fuel_consumption_curve = archetype_generation_equipment.heat_fuel_consumption_curve + _generation_system.heat_efficiency_curve = archetype_generation_equipment.heat_efficiency_curve + _generation_system.cooling_output_curve = archetype_generation_equipment.cooling_output_curve + _generation_system.cooling_fuel_consumption_curve = archetype_generation_equipment.cooling_fuel_consumption_curve + _generation_system.cooling_efficiency_curve = archetype_generation_equipment.cooling_efficiency_curve _generation_systems.append(_generation_system) energy_system.generation_systems = _generation_systems @@ -127,7 +126,7 @@ class NorthAmericaCustomEnergySystemParameters: _thermal_storage_system.maximum_operating_temperature = archetype_storage_equipment.maximum_operating_temperature _thermal_storage_system.height = archetype_storage_equipment.height _thermal_storage_system.layers = archetype_storage_equipment.layers - energy_system.energy_storage_system = _thermal_storage_system + energy_system.energy_storage_systems = _thermal_storage_system building_systems.append(energy_system) if archetype.name not in _generic_energy_systems: @@ -151,24 +150,20 @@ class NorthAmericaCustomEnergySystemParameters: _building_energy_equipment = EnergySystem() _building_energy_equipment.name = _generic_building_energy_system.name _building_energy_equipment.demand_types = _generic_building_energy_system.demand_types - - _building_distribution_system = DistributionSystem() - _building_distribution_system.generic_distribution_system = \ - copy.deepcopy(_generic_building_energy_system.distribution_system) - _building_emission_system = EmissionSystem() - _building_emission_system.generic_emission_system = \ - copy.deepcopy(_generic_building_energy_system.emission_system) - _building_generation_system = GenerationSystem() - _building_generation_system.generic_generation_system = \ - copy.deepcopy(_generic_building_energy_system.generation_system) + _generation_systems = [] + _generic_building_generation_systems = _generic_building_energy_system.generation_systems + for _generic_building_generation_system in _generic_building_generation_systems: + _building_generation_system = GenerationSystem() + _building_generation_system.generic_generation_system = \ + copy.deepcopy(_generic_building_generation_system) + _generation_systems.append(_building_generation_system) + _building_energy_equipment.generation_systems = _generation_systems _building_storage_system = ThermalStorageSystem() _building_storage_system.generic_storage_system = \ - copy.deepcopy(_generic_building_energy_system.energy_storage_system) + copy.deepcopy(_generic_building_energy_system.energy_storage_systems) - _building_energy_equipment.generation_system = _building_generation_system - _building_energy_equipment.distribution_system = _building_distribution_system - _building_energy_equipment.emission_system = _building_emission_system - _building_energy_equipment.energy_storage_system = _building_storage_system + + _building_energy_equipment.energy_storage_systems = _building_storage_system _building_energy_systems.append(_building_energy_equipment) building.energy_systems = _building_energy_systems diff --git a/hub/imports/geometry/geojson.py b/hub/imports/geometry/geojson.py index 84269cd1..c92688ee 100644 --- a/hub/imports/geometry/geojson.py +++ b/hub/imports/geometry/geojson.py @@ -116,6 +116,7 @@ class Geojson: if self._extrusion_height_field is not None: extrusion_height = float(feature['properties'][self._extrusion_height_field]) lod = 1 + self._max_z = max(self._max_z, extrusion_height) year_of_construction = None if self._year_of_construction_field is not None: year_of_construction = int(feature['properties'][self._year_of_construction_field]) diff --git a/hub/imports/results/energy_plus_workflow.py b/hub/imports/results/energy_plus.py similarity index 99% rename from hub/imports/results/energy_plus_workflow.py rename to hub/imports/results/energy_plus.py index 627b3fd7..773aca46 100644 --- a/hub/imports/results/energy_plus_workflow.py +++ b/hub/imports/results/energy_plus.py @@ -6,13 +6,16 @@ Project Coder Saeed Ranjbar saeed.ranjbar@concordia.ca Project collaborator Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca """ from pathlib import Path -from hub.helpers.monthly_values import MonthlyValues import csv +from hub.helpers.monthly_values import MonthlyValues import hub.helpers.constants as cte -class EnergyPlusWorkflow: +class EnergyPlus: + """ + Energy plus class + """ def __init__(self, city, base_path): self._city = city self._base_path = base_path diff --git a/hub/imports/results/insel_monthly_energry_balance.py b/hub/imports/results/insel_monthly_energry_balance.py index 1e63bef2..2172f891 100644 --- a/hub/imports/results/insel_monthly_energry_balance.py +++ b/hub/imports/results/insel_monthly_energry_balance.py @@ -59,7 +59,7 @@ class InselMonthlyEnergyBalance: lighting_density = thermal_zone.lighting.density appliances_density = thermal_zone.appliances.density - for month in range(0, 12): + for i_month, month in enumerate(cte.MONTHS): total_dhw_demand = 0 total_lighting = 0 total_appliances = 0 @@ -69,7 +69,7 @@ class InselMonthlyEnergyBalance: for value in schedule.values: total_day += value for day_type in schedule.day_types: - total_lighting += total_day * cte.WEEK_DAYS_A_MONTH[day_type][month] \ + total_lighting += total_day * cte.WEEK_DAYS_A_MONTH[month][day_type] \ * lighting_density / cte.WATTS_HOUR_TO_JULES lighting_demand.append(total_lighting * area) @@ -78,7 +78,7 @@ class InselMonthlyEnergyBalance: for value in schedule.values: total_day += value for day_type in schedule.day_types: - total_appliances += total_day * cte.WEEK_DAYS_A_MONTH[day_type][month] \ + total_appliances += total_day * cte.WEEK_DAYS_A_MONTH[month][day_type] \ * appliances_density / cte.WATTS_HOUR_TO_JULES appliances_demand.append(total_appliances * area) @@ -89,9 +89,9 @@ class InselMonthlyEnergyBalance: for day_type in schedule.day_types: demand = ( peak_flow * cte.WATER_DENSITY * cte.WATER_HEAT_CAPACITY - * (service_temperature - cold_water[month]) / cte.WATTS_HOUR_TO_JULES + * (service_temperature - cold_water[i_month]) / cte.WATTS_HOUR_TO_JULES ) - total_dhw_demand += total_day * cte.WEEK_DAYS_A_MONTH[day_type][month] * demand + total_dhw_demand += total_day * cte.WEEK_DAYS_A_MONTH[month][day_type] * demand domestic_hot_water_demand.append(total_dhw_demand * area) except AttributeError: domestic_hot_water_demand = [0] * 12 diff --git a/hub/imports/results_factory.py b/hub/imports/results_factory.py index fac60de3..ed9ccc8b 100644 --- a/hub/imports/results_factory.py +++ b/hub/imports/results_factory.py @@ -10,7 +10,7 @@ from pathlib import Path from hub.helpers.utils import validate_import_export_type from hub.imports.results.insel_monthly_energry_balance import InselMonthlyEnergyBalance from hub.imports.results.simplified_radiosity_algorithm import SimplifiedRadiosityAlgorithm -from hub.imports.results.energy_plus_workflow import EnergyPlusWorkflow +from hub.imports.results.energy_plus import EnergyPlus class ResultFactory: """ @@ -50,7 +50,7 @@ class ResultFactory: """ Enrich the city with energy plus results """ - EnergyPlusWorkflow(self._city, self._base_path).enrich() + EnergyPlus(self._city, self._base_path).enrich() def enrich(self): """ diff --git a/hub/persistence/repositories/city_object.py b/hub/persistence/repositories/city_object.py index aa69a0e3..4c8513ec 100644 --- a/hub/persistence/repositories/city_object.py +++ b/hub/persistence/repositories/city_object.py @@ -7,7 +7,7 @@ Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca import datetime import logging -from sqlalchemy import select, or_ +from sqlalchemy import select from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.orm import Session diff --git a/hub/version.py b/hub/version.py index f9197b15..7af64bef 100644 --- a/hub/version.py +++ b/hub/version.py @@ -1,4 +1,4 @@ """ Hub version number """ -__version__ = '0.1.8.10' +__version__ = '0.1.8.11' diff --git a/setup.py b/setup.py index 3d0e70e2..c44df2fd 100644 --- a/setup.py +++ b/setup.py @@ -18,24 +18,22 @@ with open(version) as f: exec(f.read(), main_ns) - - setup( name='cerc-hub', version=main_ns['__version__'], - description="CERC Hub consist in a set of classes (Central data model), importers and exporters to help researchers " - "to create better and sustainable cities", - long_description="CERC Hub consist in a set of classes (Central data model), importers and exporters to help " - "researchers to create better and sustainable cities.\n\nDevelop at Concordia university in canada " - "as part of the research group from the next generation cities institute our aim among others it's " + description="CERC Hub consist of a set of classes (Central data model), importers and exporters to help researchers " + "to create better and more sustainable cities", + long_description="CERC Hub consist of a set of classes (Central data model), importers and exporters to help " + "researchers to create better and more sustainable cities.\n\nDeveloped at Concordia university in Canada " + "as part of the research group from the Next Generation Cities Institute, our aim among others is " "to provide a comprehensive set of tools to help researchers and urban developers to make decisions " "to improve the livability and efficiency of our cities", classifiers=[ - "License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)", - "Programming Language :: Python", - "Programming Language :: Python :: 3", - ], - include_package_data=True, + "License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + ], + include_package_data=True, packages=['hub', 'hub.catalog_factories', 'hub.catalog_factories.construction', @@ -88,7 +86,8 @@ setup( data_files=[ ('hub', glob.glob('requirements.txt')), ('hub/config', glob.glob('hub/config/*.ini')), - ('hub/catalog_factories/greenery/ecore_greenery', glob.glob('hub/catalog_factories/greenery/ecore_greenery/*.ecore')), + ('hub/catalog_factories/greenery/ecore_greenery', + glob.glob('hub/catalog_factories/greenery/ecore_greenery/*.ecore')), ('hub/data/construction', glob.glob('hub/data/construction/*')), ('hub/data/costs', glob.glob('hub/data/costs/montreal_costs.xml')), ('hub/data/customized_imports', glob.glob('hub/data/customized_imports/ashrae_archetypes.xml')), @@ -109,4 +108,4 @@ setup( ('hub/exports/building_energy/idf_files', glob.glob('hub/exports/building_energy/idf_files/*.idd')) ], -) +) \ No newline at end of file diff --git a/tests/test_exports.py b/tests/test_exports.py index 3bb0f91f..ff808968 100644 --- a/tests/test_exports.py +++ b/tests/test_exports.py @@ -66,12 +66,7 @@ class TestExports(TestCase): def _export(self, export_type, from_pickle=False): self._complete_city = self._get_complete_city(from_pickle) - try: - ExportsFactory(export_type, self._complete_city, self._output_path).export() - except ValueError as err: - if export_type != 'stl': - logging.warning('No backend export for STL test, skipped') - raise err + ExportsFactory(export_type, self._complete_city, self._output_path).export() def _export_building_energy(self, export_type, from_pickle=False): self._complete_city = self._get_complete_city(from_pickle) @@ -83,12 +78,6 @@ class TestExports(TestCase): """ self._export('obj', False) - def test_stl_export(self): - """ - export to stl - """ - self._export('stl', False) - def test_energy_ade_export(self): """ export to energy ADE diff --git a/tests/test_results_import.py b/tests/test_results_import.py index 8f4e0aed..197e185c 100644 --- a/tests/test_results_import.py +++ b/tests/test_results_import.py @@ -40,7 +40,7 @@ class TestResultsImport(TestCase): function_to_hub=Dictionaries().montreal_function_to_hub_function).city ConstructionFactory('nrcan', self._city).enrich() - UsageFactory('nrcan', self._city).enrich() + UsageFactory('comnet', self._city).enrich() def test_sra_import(self): ExportsFactory('sra', self._city, self._output_path).export() diff --git a/tests/test_systems_factory.py b/tests/test_systems_factory.py index 4dd70998..07c9683a 100644 --- a/tests/test_systems_factory.py +++ b/tests/test_systems_factory.py @@ -98,15 +98,15 @@ class TestSystemsFactory(TestCase): ) _building_generation_system = GenerationSystem() _building_generation_system.generic_generation_system = ( - copy.deepcopy(_generic_building_energy_system.generation_system) + copy.deepcopy(_generic_building_energy_system.generation_systems) ) if cte.HEATING in _building_energy_equipment.demand_types: _building_generation_system.heat_power = building.heating_peak_load[cte.YEAR][0] if cte.COOLING in _building_energy_equipment.demand_types: _building_generation_system.cooling_power = building.cooling_peak_load[cte.YEAR][0] - _building_energy_equipment.generation_system = _building_generation_system - _building_energy_equipment.distribution_system = _building_distribution_system - _building_energy_equipment.emission_system = _building_emission_system + _building_energy_equipment.generation_systems = _building_generation_system + _building_energy_equipment.distribution_systems = _building_distribution_system + _building_energy_equipment.emission_systems = _building_emission_system _building_energy_systems.append(_building_energy_equipment) building.energy_systems = _building_energy_systems @@ -161,27 +161,27 @@ class TestSystemsFactory(TestCase): _building_distribution_system = DistributionSystem() _building_distribution_system.generic_distribution_system = ( - copy.deepcopy(_generic_building_energy_system.distribution_system) + copy.deepcopy(_generic_building_energy_system.distribution_systems) ) _building_emission_system = EmissionSystem() _building_emission_system.generic_emission_system = ( - copy.deepcopy(_generic_building_energy_system.emission_system) + copy.deepcopy(_generic_building_energy_system.emission_systems) ) _building_generation_system = GenerationSystem() _building_generation_system.generic_generation_system = ( - copy.deepcopy(_generic_building_energy_system.generation_system) + copy.deepcopy(_generic_building_energy_system.generation_systems) ) _building_storage_system = ThermalStorageSystem() _building_storage_system.generic_storage_system = \ - copy.deepcopy(_generic_building_energy_system.energy_storage_system) + copy.deepcopy(_generic_building_energy_system.energy_storage_systems) if cte.HEATING in _building_energy_equipment.demand_types: _building_generation_system.heat_power = building.heating_peak_load[cte.YEAR][0] if cte.COOLING in _building_energy_equipment.demand_types: _building_generation_system.cooling_power = building.cooling_peak_load[cte.YEAR][0] - _building_energy_equipment.generation_system = _building_generation_system - _building_energy_equipment.distribution_system = _building_distribution_system - _building_energy_equipment.emission_system = _building_emission_system + _building_energy_equipment.generation_systems = _building_generation_system + _building_energy_equipment.distribution_systems = _building_distribution_system + _building_energy_equipment.emission_systems = _building_emission_system _building_energy_systems.append(_building_energy_equipment) building.energy_systems = _building_energy_systems