""" TestMebWorkflow tests and validates the complete Monthly Energy Balance workflow SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2020 Project Author Pilar Monsalvete pilar_monsalvete@yahoo.es """ from pathlib import Path from unittest import TestCase import numpy as np import subprocess from subprocess import SubprocessError, TimeoutExpired, CalledProcessError from insel.insel import Insel from insel.templates.monthly_energy_balance import MonthlyEnergyBalance as templates from factories.geometry_factory import GeometryFactory from populate import Populate from factories.weather_factory import WeatherFactory from helpers import monthly_values as mv from simplified_radiosity_algorithm.simplified_radiosity_algorithm import SimplifiedRadiosityAlgorithm as sralgorithm from city_model_structure.city import City class TestMebWorkflow(TestCase): """ TestMebWorkflow TestCase 1 """ def setUp(self) -> None: """ Test setup :return: None """ self._example_path = (Path(__file__).parent.parent / 'tests_data').resolve() self._geometry_type = 'citygml' self._use_cached_sra_file = False self._input_geometry_file = (self._example_path / 'gis' / '2050 bp_2buildings.gml').resolve() self._project_folder = Path(__file__).parent.parent self._cli_weather_file = (self._example_path / 'weather' / 'inseldb_new_york_city.cli').resolve() self._city_gml = None self._city = None self._populated_city = None self._monthly_temperatures = None self._city_with_weather = None self._city_with_cli = None self._city_with_dat = None self._pickle_file = (self._example_path / 'gis' / 'kelowna_test_case.pickle').resolve() self._pickle_file_populated = Path(str(self._pickle_file).replace('.pickle', '_populated.pickle')) self._pickle_file_populated_weather = Path(str(self._pickle_file_populated).replace('.pickle', '_weather.pickle')) self._city_name = 'Summerland' def _get_citygml(self, use_pickle=False): if self._city_gml is None: if use_pickle: self._city_gml = City.load(self._pickle_file) else: file_path = self._input_geometry_file self._city_gml = GeometryFactory('citygml', file_path).city self.assertIsNotNone(self._city_gml, 'city is none') return self._city_gml def _get_citygml_populated(self, use_pickle): if self._populated_city is None: self._city = self._get_citygml(use_pickle=use_pickle) self._populated_city = Populate(self._city).populated_city return self._populated_city def _get_citygml_with_weather(self, use_pickle): if self._city_with_weather is None: self._city_with_weather = self._get_citygml(use_pickle=use_pickle) weather_path = (self._example_path / 'weather').resolve() WeatherFactory('dat', self._city_with_weather, city_name=self._city_name, base_path=weather_path) for building in self._city_with_weather.buildings: building.external_temperature['month'] = mv.MonthlyValues(). \ get_mean_values(building.external_temperature['hour'][['inseldb']]) sra_file_name = 'SRA' sra = sralgorithm(Path(self._project_folder).resolve(), sra_file_name, Path(self._cli_weather_file).resolve(), self._city_with_weather.city_objects, lower_corner=self._city_with_weather.lower_corner) if self._use_cached_sra_file: sra.results() else: sra.call_sra(keep_files=True) sra.set_irradiance_surfaces(self._city_with_weather) return self._city_with_weather def _get_cli_single_building(self, building_name, radius, use_pickle): self._city_with_cli = self._get_citygml(use_pickle=use_pickle) building = self._city_with_cli.city_object(building_name) new_city = self._city_with_cli.region(building.location, radius) sra_file_name = 'SRA' print('location', building.location) print('lower corner', new_city.lower_corner) full_path_cli = (self._example_path / 'weather' / 'inseldb_Summerland.cli').resolve() sra = sralgorithm(Path(self._project_folder).resolve(), sra_file_name, full_path_cli, new_city.city_objects, lower_corner=new_city.lower_corner) sra.call_sra(keep_files=True) sra.set_irradiance_surfaces(self._city_with_cli, building_name=building_name) return self._city_with_cli def _get_city_with_dat(self, use_pickle): if self._city_with_dat is None: self._city_with_dat = self._get_citygml(use_pickle=use_pickle) weather_path = (self._example_path / 'weather').resolve() WeatherFactory('dat', self._city_with_dat, city_name=self._city_name, base_path=weather_path) for building in self._city_with_dat.buildings: building.external_temperature['month'] = mv.MonthlyValues(). \ get_mean_values(building.external_temperature['hour'][['inseldb']]) return self._city_with_dat def test_populate_city(self): """ Test populate class :return: none """ # populated_city = self._get_citygml_populated(True) # populated_city.save(pickle_file_populated) populated_city = City.load(self._pickle_file_populated) self.assertIsNotNone(populated_city.city_objects, 'city_objects is none') for building in populated_city.buildings: self.assertIsNotNone(building.usage_zones, 'city_object return none') self.assertIsNotNone(building.thermal_zones, 'city_object return none') def test_weather_assignment(self): """ Test the weather assignment :return: none """ weather_city = self._get_citygml_with_weather(False) for building in weather_city.buildings: self.assertFalse(building.external_temperature['month'].empty, 'monthly external temperature return none') for surface in building.surfaces: if surface.type != 'Ground': self.assertIsNotNone(surface.global_irradiance['month'], 'monthly irradiance return none') def test_insel_call(self): """ Test the insel template generation and engine call :return: none """ self._get_citygml_populated(False) city = self._get_citygml_with_weather(False) expected_values = [[13619.57, 3.65], [14886.33, 1.67]] i = 0 for building in city.buildings: full_path_out = Path(self._project_folder / 'outputs' / (building.name + '_insel.out')).resolve() full_path_out.parent.mkdir(parents=True, exist_ok=True) insel_file_name = building.name + '.insel' content = templates.generate_meb_template(building, full_path_out) self.assertIsNotNone(content, 'content return empty') Insel(Path(self._project_folder).resolve(), insel_file_name, content, mode=2, keep_files=True).run() building.heating['month'], building.cooling['month'] = templates.demand(full_path_out) values = building.heating['month'][['INSEL']].to_numpy() self.assertEqual(expected_values[i][0], np.around(float(values[11]), decimals=2), 'wrong value monthly heating') values = building.cooling['month'][['INSEL']].to_numpy() self.assertEqual(expected_values[i][1], np.around(float(values[11]), decimals=2), 'wrong value monthly cooling') i += 1 def test_city_with_weather_building_by_building(self): radius = 100 building_names = ['BLD100086', 'BLD131702', 'BLD132148', 'BLD126221', 'BLD131081', 'BLD135303', 'BLD130088', 'BLD128703', 'BLD121900', 'BLD141378', 'BLD135375', 'BLD126801', 'BLD120774', 'BLD118577', 'BLD129395', 'BLD126848', 'BLD115972', 'BLD138959', 'BLD122103', 'BLD114335', 'BLD124272', 'BLD107027', 'BLD105415', 'BLD129867', 'BLD133164', 'BLD119241', 'BLD106658', 'BLD114097', 'BLD130182', 'BLD121456', 'BLD123516', 'BLD126061', 'BLD128845', 'BLD138802', 'BLD129673'] building_names = ['BLD100086'] city = self._get_city_with_dat(True) for building in city.buildings: self.assertTrue(building.external_temperature, 'external temperature return none') for building_name in building_names: print(building_name) weather_city = self._get_cli_single_building(building_name, radius, True) # for building in weather_city.city_objects: # if building.name == building_name: # for surface in building.surfaces: # if surface.type != 'Ground': # self.assertTrue(surface.global_irradiance, 'global irradiance return none in calculated building') # else: # for surface in building.surfaces: # self.assertFalse(surface.global_irradiance, 'global irradiance return not none in not calculated building') def test_sra(self): _executable = 'shortwave_integer' _full_path_in = (Path(__file__).parent.parent / 'tmp\SRA.xml').resolve() try: completed = subprocess.run([_executable, str(_full_path_in)]) except (SubprocessError, TimeoutExpired, CalledProcessError) as error: raise Exception(error)