From e4b6c54af6168b2bf3268006e2790ef644f46574 Mon Sep 17 00:00:00 2001 From: guille Date: Thu, 27 Apr 2023 10:59:03 -0400 Subject: [PATCH] Partial correction for peakloads --- hub/city_model_structure/city.py | 5 +- .../insel/insel_monthly_energy_balance.py | 12 +++- .../energy_building_exports_factory.py | 3 - hub/exports/exports_factory.py | 1 + .../formats/simplified_radiosity_algorithm.py | 8 ++- .../results/insel_monthly_energry_balance.py | 2 +- hub/imports/results/peak_load.py | 12 ++-- hub/imports/results_factory.py | 9 +-- hub/unittests/test_imports.py | 64 +++++++++++++++++++ 9 files changed, 93 insertions(+), 23 deletions(-) create mode 100644 hub/unittests/test_imports.py diff --git a/hub/city_model_structure/city.py b/hub/city_model_structure/city.py index 987a47e1..e8a34595 100644 --- a/hub/city_model_structure/city.py +++ b/hub/city_model_structure/city.py @@ -122,6 +122,8 @@ class City: Get the name for the climatic information reference city :return: None or str """ + if self._climate_reference_city is None: + self._climate_reference_city = self._get_location().city return self._climate_reference_city @climate_reference_city.setter @@ -130,8 +132,7 @@ class City: Set the name for the climatic information reference city :param value: str """ - if value is not None: - self._climate_reference_city = str(value) + self._climate_reference_city = str(value) @property def climate_file(self) -> Union[None, Path]: diff --git a/hub/exports/building_energy/insel/insel_monthly_energy_balance.py b/hub/exports/building_energy/insel/insel_monthly_energy_balance.py index 6b07179a..9814496a 100644 --- a/hub/exports/building_energy/insel/insel_monthly_energy_balance.py +++ b/hub/exports/building_energy/insel/insel_monthly_energy_balance.py @@ -51,6 +51,7 @@ class InselMonthlyEnergyBalance(Insel): ) self._export() + def _export(self): for i_file, content in enumerate(self._contents): file_name = self._insel_files_paths[i_file] @@ -94,12 +95,19 @@ class InselMonthlyEnergyBalance(Insel): inputs.append(f"{str(100 + i)}.1 % Radiation surface {str(i)}") number_of_storeys = int(building.eave_height / building.average_storey_height) + attic_heated = building.attic_heated + basement_heated = building.basement_heated + if building.attic_heated is None: + attic_heated = 0 + if building.basement_heated is None: + basement_heated = 0 + # BUILDING PARAMETERS parameters = [f'{building.volume} % BP(1) Heated Volume (m3)', f'{building.average_storey_height} % BP(2) Average storey height (m)', f'{number_of_storeys} % BP(3) Number of storeys above ground', - f'{building.attic_heated} % BP(4) Attic heating type (0=no room, 1=unheated, 2=heated)', - f'{building.basement_heated} % BP(5) Cellar heating type (0=no room, 1=unheated, 2=heated, ' + f'{attic_heated} % BP(4) Attic heating type (0=no room, 1=unheated, 2=heated)', + f'{basement_heated} % BP(5) Cellar heating type (0=no room, 1=unheated, 2=heated, ' f'99=invalid)'] # todo: this method and the insel model have to be reviewed for more than one internal zone diff --git a/hub/exports/energy_building_exports_factory.py b/hub/exports/energy_building_exports_factory.py index 0b39ebd0..46e233ea 100644 --- a/hub/exports/energy_building_exports_factory.py +++ b/hub/exports/energy_building_exports_factory.py @@ -55,9 +55,7 @@ class EnergyBuildingsExportsFactory: """ idf_data_path = (Path(__file__).parent / './building_energy/idf_files/').resolve() # todo: create a get epw file function based on the city - #print('path', idf_data_path) weather_path = (Path(__file__).parent / '../data/weather/epw/CAN_PQ_Montreal.Intl.AP.716270_CWEC.epw').resolve() - #print(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, adjacent_buildings=self._adjacent_buildings) @@ -74,7 +72,6 @@ class EnergyBuildingsExportsFactory: Export the city given to the class using the given export type handler :return: None """ - print(self) return getattr(self, self._export_type, lambda: None) def export_debug(self): diff --git a/hub/exports/exports_factory.py b/hub/exports/exports_factory.py index ae99dd0d..2ac2ec95 100644 --- a/hub/exports/exports_factory.py +++ b/hub/exports/exports_factory.py @@ -79,6 +79,7 @@ class ExportsFactory: Export the city to Simplified Radiosity Algorithm xml format :return: None """ + print(self._weather_format, self._weather_file) return SimplifiedRadiosityAlgorithm(self._city, (self._path / f'{self._city.name}_sra.xml'), self._weather_file, diff --git a/hub/exports/formats/simplified_radiosity_algorithm.py b/hub/exports/formats/simplified_radiosity_algorithm.py index e2fa2ab9..b6de68f6 100644 --- a/hub/exports/formats/simplified_radiosity_algorithm.py +++ b/hub/exports/formats/simplified_radiosity_algorithm.py @@ -4,6 +4,8 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2022 Concordia CERC group Project Coder Guillermo.GutierrezMorote@concordia.ca """ +from pathlib import Path + import xmltodict from hub.imports.weather_factory import WeatherFactory @@ -32,9 +34,13 @@ class SimplifiedRadiosityAlgorithm: self._end_month = end_month self._end_day = end_day self._city = city + self._city.climate_file = str((Path(file_name).parent / f'{city.name}.cli').resolve()) + self._city.climate_reference_city = city.location + print(city.location) self._target_buildings = target_buildings self._weather_format = weather_format self._weather_file = weather_file + self._export() def _correct_point(self, point): @@ -45,8 +51,8 @@ class SimplifiedRadiosityAlgorithm: return [x, y, z] def _export(self): - self._export_sra_xml() self._export_sra_cli() + self._export_sra_xml() def _export_sra_cli(self): file = self._city.climate_file diff --git a/hub/imports/results/insel_monthly_energry_balance.py b/hub/imports/results/insel_monthly_energry_balance.py index 15f2882b..a2b5b322 100644 --- a/hub/imports/results/insel_monthly_energry_balance.py +++ b/hub/imports/results/insel_monthly_energry_balance.py @@ -12,7 +12,7 @@ import hub.helpers.constants as cte class InselMonthlyEnergyBalance: """ - Import SRA results + Import insel monthly energy balance results """ def __init__(self, city, base_path): diff --git a/hub/imports/results/peak_load.py b/hub/imports/results/peak_load.py index 9ace3104..ea5f4e06 100644 --- a/hub/imports/results/peak_load.py +++ b/hub/imports/results/peak_load.py @@ -3,15 +3,18 @@ from hub.imports.results.peak_calculation.loads_calculation import LoadsCalculat class PeakLoad: - _MONTH_STARTING_HOUR = [0, 744, 1416, 2160, 2880, 3624, 4344, 5088, 5832, 6552, 7296, 8016] def __init__(self, city): self._city = city self._weather_format = 'epw' + self._irradiance_format = 'sra' def enrich(self): for building in self._city.buildings: + if building.heating + + monthly_heating_loads = [] monthly_cooling_loads = [] ambient_temperature = building.external_temperature[cte.HOUR][self._weather_format] @@ -19,7 +22,6 @@ class PeakLoad: ground_temperature = building.ground_temperature[cte.MONTH]['2'][month] heating_ambient_temperature = 100 cooling_ambient_temperature = -100 - heating_calculation_hour = -1 cooling_calculation_hour = -1 start_hour = self._MONTH_STARTING_HOUR[month] end_hour = 8760 @@ -29,7 +31,6 @@ class PeakLoad: temperature = ambient_temperature[hour] if temperature < heating_ambient_temperature: heating_ambient_temperature = temperature - heating_calculation_hour = hour if temperature > cooling_ambient_temperature: cooling_ambient_temperature = temperature cooling_calculation_hour = hour @@ -55,7 +56,6 @@ class PeakLoad: cooling_load = 0 monthly_heating_loads.append(heating_load) monthly_cooling_loads.append(cooling_load) - - self._results[building.name] = {'monthly heating peak load': monthly_heating_loads, + building. {'monthly heating peak load': monthly_heating_loads, 'monthly cooling peak load': monthly_cooling_loads} - self._print_results() + diff --git a/hub/imports/results_factory.py b/hub/imports/results_factory.py index 4eb7c0e4..5fd542bc 100644 --- a/hub/imports/results_factory.py +++ b/hub/imports/results_factory.py @@ -9,7 +9,6 @@ from pathlib import Path from hub.helpers.utils import validate_import_export_type from hub.hub_logger import logger -from hub.imports.results.peak_load import PeakLoad from hub.imports.results.simplified_radiosity_algorithm import SimplifiedRadiosityAlgorithm from hub.imports.results.insel_monthly_energry_balance import InselMonthlyEnergyBalance from hub.imports.results.insel_heatpump_energy_demand import InselHeatPumpEnergyDemand @@ -54,18 +53,12 @@ class ResultFactory: """ InselHeatPumpEnergyDemand(self._city, self._base_path, self._hp_model).enrich() - def _insel_meb(self): + def _insel_monthly_energy_balance(self): """ Enrich the city with insel monthly energy balance results """ InselMonthlyEnergyBalance(self._city, self._base_path).enrich() - def _peak_load(self): - """ - Enrich the city with peak load results - """ - PeakLoad(self._city).enrich() - def enrich(self): """ Enrich the city given to the class using the usage factory given handler diff --git a/hub/unittests/test_imports.py b/hub/unittests/test_imports.py new file mode 100644 index 00000000..e435e51c --- /dev/null +++ b/hub/unittests/test_imports.py @@ -0,0 +1,64 @@ +""" +TestExports test and validate the city export formats +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca +""" +import subprocess +from pathlib import Path +from unittest import TestCase +import pandas as pd +from hub.imports.geometry_factory import GeometryFactory +from hub.helpers.dictionaries import Dictionaries +from hub.imports.construction_factory import ConstructionFactory +from hub.imports.usage_factory import UsageFactory +from hub.exports.exports_factory import ExportsFactory +from hub.exports.energy_building_exports_factory import EnergyBuildingsExportsFactory +from hub.imports.results_factory import ResultFactory +import hub.helpers.constants as cte +from hub.city_model_structure.city import City + + +class TestImports(TestCase): + """ + TestImports class contains the unittest for import functionality + """ + def setUp(self) -> None: + """ + Test setup + :return: None + """ + self._example_path = (Path(__file__).parent / 'tests_data').resolve() + self._gml_path = (self._example_path / 'FZK_Haus_LoD_2.gml').resolve() + self._output_path = (Path(__file__).parent / 'tests_outputs').resolve() + self._city = GeometryFactory('citygml', + self._gml_path, + function_to_hub=Dictionaries().alkis_function_to_hub_function).city + ConstructionFactory('nrcan', self._city).enrich() + UsageFactory('nrcan', self._city).enrich() + + def test_sra_import(self): + weather_file = (self._example_path / 'CAN_PQ_Montreal.Intl.AP.716270_CWEC.epw').resolve() + ExportsFactory('sra', self._city, self._output_path, weather_file=weather_file, weather_format='epw').export() + sra_path = (self._output_path / f'{self._city.name}_sra.xml').resolve() + subprocess.run(['sra', str(sra_path)]) + ResultFactory('sra', self._city, self._output_path).enrich() + # Check that all the buildings has radiance in the surfaces + for building in self._city.buildings: + for surface in building.surfaces: + self.assertIsNotNone(surface.global_irradiance) + + def test_meb_import(self): + weather_file = (self._example_path / 'CAN_PQ_Montreal.Intl.AP.716270_CWEC.epw').resolve() + ExportsFactory('sra', self._city, self._output_path, weather_file=weather_file, weather_format='epw').export() + sra_path = (self._output_path / f'{self._city.name}_sra.xml').resolve() + subprocess.run(['sra', str(sra_path)]) + ResultFactory('sra', self._city, self._output_path).enrich() + EnergyBuildingsExportsFactory('insel_monthly_energy_balance', self._city, self._output_path).export() + for building in self._city.buildings: + insel_path = (self._output_path / f'{building.name}.insel') + subprocess.run(['insel', str(insel_path)]) + ResultFactory('insel_monthly_energy_balance', self._city, self._output_path) + for building in self._city.buildings: + print(building.heating) + self.assertIsNotNone(None) \ No newline at end of file