workflow v1.0

This commit is contained in:
Pilar 2022-11-25 14:20:10 -05:00
parent e9bed8affc
commit 16c36f1112
6 changed files with 100 additions and 533 deletions

View File

@ -1,12 +1,16 @@
# MonthlyEnergyBalance
This tool calculates the monthly energy balance for a given region.
This tool calculates the monthly energy balance for each building in a given region.
The current version can only use NYC CityGml at LOD1, but we will increase the regions and the level of detail in future releases.
The following assumptions are taken:
- No building in the region have attics
- All buildings have basement but those are not heated
- The construction details come from nrel
- The usage details come from comnet
#### dependencies
#### Dependencies
You will need to install the following dependencies in your computer order to run the software; please take a look at the [install process](#installation) for your system-specific details
You will need to install the following dependencies in your computer in order to run the software; please take a look at the [install process](#installation) for your system-specific details
##### External software
+ INSEL 8 (https://insel4d.ca/en/download.html)
@ -14,29 +18,6 @@ You will need to install the following dependencies in your computer order to ru
After installing these tools you should include their paths in Path.
##### Python libraries
+ Shapely (1.7.0)
+ cycler (0.10.0)
+ geographiclib (1.50)
+ geopy (1.21.0)
+ kiwisolver (1.2.0)
+ matplotlib (3.2.1)
+ numpy (1.18.3)
+ numpy-stl (2.11.2)
+ pandas (1.0.3)
+ pip (20.0.2)
+ pyny3d (0.2)
+ pyparsing (2.4.7)
+ pyproj (2.6.0)
+ python-dateutil (2.8.1)
+ python-utils (2.4.0)
+ pytz (2019.3)
+ scipy (1.4.1)
+ setuptools (46.1.3)
+ six (1.14.0)
+ stl (0.0.3)
+ xmltodict (0.12.0)
## installation
##### Linux / Mac
@ -81,5 +62,3 @@ $ python main.py
```
c:\> python.exe main.py
```

View File

@ -1,60 +1,18 @@
import os
from pathlib import Path
from abc import ABC
class Insel:
def __init__(self, path, name, new_content="", mode=1, keep_files=False):
class Insel(ABC):
def __init__(self, path):
self._path = path
self._name = name
self._full_path = None
self._content = None
self._results = None
self._keep_files = keep_files
self.add_content(new_content, mode)
self.save()
def save(self):
with open(self.full_path, 'w') as insel_file:
insel_file.write(self.content)
return
@property
def full_path(self):
if self._full_path is None:
self._full_path = (Path(self._path) / 'tmp' / self._name).resolve()
return self._full_path
@property
def content(self):
if self._content is None:
if os.path.exists(self.full_path):
with open(self.full_path, 'r') as insel_file:
self._content = insel_file.read()
else:
self._content = ''
return self._content
# todo: create method
def add_block(self):
raise Exception('Not implemented')
def add_content(self, new_content, mode):
# mode = 1: keep old content
if mode == 1:
self._content = self.content + '\r\n' + new_content
# mode = 2: over-write
elif mode == 2:
self._content = new_content
else:
raise Exception('Add content mode not supported')
return
def run(self):
output = os.system('insel ' + str(self.full_path))
# todo: catch errors from INSEL
if not self._keep_files:
os.remove(self.full_path)
paths = sorted(Path(self._path).glob('*.insel'))
for file in paths:
os.system('insel ' + str(file))
@property
def results(self):
raise Exception('Not implemented')
raise NotImplementedError

View File

@ -7,26 +7,23 @@ Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.mons
from pathlib import Path
import pandas as pd
import sys
from insel.templates.monthly_energy_balance import MonthlyEnergyBalance as templates
import csv
from insel.insel import Insel
class MonthlyDemandCalculation:
class MonthlyDemandCalculation(Insel):
def __init__(self, city, main_path, weather_format):
super().__init__(main_path)
self._city = city
self._main_path = main_path
self._weather_format = weather_format
def monthly_demand(self):
def results(self):
for building in self._city.buildings:
full_path_out = Path(self._main_path + '/outputs/' + building.name + '_insel.out').resolve()
file_name = building.name + '.out'
full_path_out = Path(self._path / file_name).resolve()
full_path_out.parent.mkdir(parents=True, exist_ok=True)
insel_file_name = building.name + '.insel'
try:
content = templates.generate_meb_template(building, full_path_out, self._weather_format)
insel = Insel(Path(self._main_path).resolve(), insel_file_name, content, mode=2, keep_files=True).run()
building.heating['month'], building.cooling['month'] = templates.demand(full_path_out)
building.heating['month'], building.cooling['month'] = self._demand(full_path_out)
heating_year = 0
for value in building.heating['month']['INSEL']:
if value == 'NaN':
@ -47,3 +44,21 @@ class MonthlyDemandCalculation:
print(sys.exc_info()[1])
print('Building ' + building.name + ' could not be processed')
continue
@staticmethod
def _demand(insel_outputs_path):
heating = []
cooling = []
with open(Path(insel_outputs_path).resolve()) as csv_file:
csv_reader = csv.reader(csv_file)
for line in csv_reader:
demand = str(line).replace("['", '').replace("']", '').split()
for i in range(0, 2):
if demand[i] != 'NaN':
aux = float(demand[i])*1000 # kWh to Wh
demand[i] = str(aux)
heating.append(demand[0])
cooling.append(demand[1])
monthly_heating = pd.DataFrame(heating, columns=['INSEL'])
monthly_cooling = pd.DataFrame(cooling, columns=['INSEL'])
return monthly_heating, monthly_cooling

View File

@ -1,177 +0,0 @@
import helpers.library_codes
import numpy as np
from pathlib import Path
import pandas as pd
import csv
from imports.weather.helpers.weather import Weather as wt
import helpers.constants as cte
class MonthlyEnergyBalance:
@staticmethod
def generate_meb_template(building, insel_outputs_path, key):
lc = helpers.library_codes.LibraryCodes()
file = ""
file += "s 1 do\r\n"
file += "p 1 1 12 1\r\n"
file += "\r\n"
file += "s 4 d18599 1.1 20.1 21.1\r\n"
surfaces = building.surfaces
for i in range(1, len(surfaces) + 1):
file += str(100 + i) + '.1 % Radiation surface ' + str(i) + '\n'
file += 'p 4' + '\n'
# BUILDING PARAMETERS
file += str(0.85*building.volume) + ' % BP(1) Heated Volume (vBrutto)\n'
file += str(building.average_storey_height) + ' % BP(2) Average storey height / m\n'
file += str(building.storeys_above_ground) + ' % BP(3) Number of storeys above ground\n'
file += str(building.attic_heated) + ' % BP(4) Attic heating type (0=no room, 1=unheated, 2=heated)\n'
file += str(building.basement_heated) + ' % BP(5) Cellar heating type (0=no room, 1=unheated, ' \
'2=heated, 99=invalid)\n'
# todo: this method and the insel model have to be reviewed for more than one thermal zone
thermal_zone = building.thermal_zones[0]
file += str(thermal_zone.indirectly_heated_area_ratio) + ' % BP(6) Indirectly heated area ratio\n'
file += str(thermal_zone.effective_thermal_capacity) + ' % BP(7) Effective heat capacity\n'
file += str(thermal_zone.additional_thermal_bridge_u_value) + ' % BP(8) Additional U-value for heat bridge\n'
file += '0 % BP(9) Usage type (0=standard, 1=IWU)\n'
# ZONES AND SURFACES
# todo: is this actually number of thermal zones or of usage zones?
file += str(len(building.thermal_zones)) + ' % BP(10) Number $z$ of zones\n'
i = 0
for usage_zone in building.usage_zones:
percentage_usage = 1
file += str(float(building.floor_area) * percentage_usage) + ' % BP(11) #1 Area of zone ' + \
str(i + 1) + ' (sqm)' + '\n'
total_internal_gains = 0
for ig in usage_zone.internal_gains:
total_internal_gains += float(ig.average_internal_gain) * \
(float(ig.convective_fraction) + float(ig.radiative_fraction))
file += str(total_internal_gains) + ' % BP(12) #2 Internal gains of zone ' + str(i + 1) + '\n'
file += str(usage_zone.heating_setpoint) + ' % BP(13) #3 Heating setpoint temperature zone ' + \
str(i + 1) + ' (tSetHeat)' + '\n'
file += str(usage_zone.heating_setback) + ' % BP(14) #4 Heating setback temperature zone ' + \
str(i + 1) + ' (tSetbackHeat)' + '\n'
# file += str(usage_zone.cooling_setpoint) + ' % BP(15) #5 Cooling setpoint temperature zone ' + \
# str(i + 1) + ' (tSetCool)' + '\n'
file += '21 % BP(15) #5 Cooling setpoint temperature zone ' + \
str(i + 1) + ' (tSetCool)' + '\n'
file += str(usage_zone.hours_day) + ' % BP(16) #6 Usage hours per day zone ' + str(i + 1) + '\n'
file += str(usage_zone.days_year) + ' % BP(17) #7 Usage days per year zone ' + str(i + 1) + '\n'
if usage_zone.mechanical_air_change is None:
if thermal_zone.infiltration_rate_system_off is None:
raise Exception('Ventilation air rate is not initialized')
else:
file += str(thermal_zone.infiltration_rate_system_off) + ' % BP(18) #8 Minimum air change rate zone ' + \
str(i + 1) + ' (h^-1)' + '\n'
else:
file += str(usage_zone.mechanical_air_change) + ' % BP(18) #8 Minimum air change rate zone ' + \
str(i + 1) + ' (h^-1)' + '\n'
i += 1
file += str(len(surfaces)) + ' % Number of surfaces = BP(11+8z)\n'
file += '% 1. Surface type (1=wall, 2=ground 3=roof, 4=flat roof)' + '\n'
file += '% 2. Areas above ground' + '\n'
file += '% 3. Areas below ground' + '\n'
file += '% 4. U-value' + '\n'
file += '% 5. Window area' + '\n'
file += '% 6. Window frame fraction' + '\n'
file += '% 7. Window U-value' + '\n'
file += '% 8. Window g-value' + '\n'
file += '% 9. Short-wave reflectance' + '\n'
file += '% #1 #2 #3 #4 #5 #6 #7 #8 #9' + '\n'
# todo: this method has to be reviewed for more than one thermal opening per thermal boundary
for thermal_boundary in building.thermal_zones[0].bounded:
type_code = lc.construction_types_to_code(thermal_boundary.type)
if thermal_boundary.surface.holes_polygons is None:
window_area = float(thermal_boundary.surface.perimeter_polygon.area) * float(thermal_boundary.window_ratio)
else:
window_area = 0
for hole_polygon in thermal_boundary.surface.holes_polygons:
window_area += hole_polygon.area
string = type_code + ' ' + str(0.85*thermal_boundary.surface.area_above_ground) + ' ' + \
str(thermal_boundary.surface.area_below_ground) + ' ' + str(thermal_boundary.u_value) + ' ' + \
str(0.85*window_area) + ' '
if window_area <= 0.001:
string = string + '0 0 0 '
else:
string = string + str(thermal_boundary.thermal_openings[0].frame_ratio) + ' ' + \
str(thermal_boundary.thermal_openings[0].overall_u_value) + ' ' + \
str(thermal_boundary.thermal_openings[0].g_value) + ' '
if thermal_boundary.outside_solar_absorptance is not None:
string += str(thermal_boundary.shortwave_reflectance) + '\r\n'
else:
string += '0 \r\n'
file += string
file += '\r\n'
file += 's 20 polyg 1\r\n'
file += 'p 20 12 % Monthly ambient temperature\r\n'
external_temperature = building.external_temperature[cte.MONTH]
for i in range(0, len(external_temperature)):
file += str(i+1) + ' ' + str(external_temperature.at[i, key]) + '\r\n'
file += '\r\n'
file += 's 21 polyg 1\r\n'
file += 'p 21 12 % Monthly sky temperature\r\n'
i = 1
sky_temperature = wt.sky_temperature(external_temperature[[key]].to_numpy().T[0])
for temperature in sky_temperature:
file += str(i) + ' ' + str(temperature) + '\r\n'
i += 1
i = 0
for surface in surfaces:
file += '\r\n'
file += 's ' + str(101 + i) + ' polyg 1 % Monthly surface radiation (W/sqm)\r\n'
file += 'p ' + str(101 + i) + ' 12 % Azimuth ' + str(np.rad2deg(surface.azimuth)) + \
', inclination ' + str(np.rad2deg(surface.inclination)) + ' degrees\r\n'
if surface.type != 'Ground':
global_irradiance = surface.global_irradiance[cte.MONTH]
for j in range(0, len(global_irradiance)):
file += str(j + 1) + ' ' + str(global_irradiance.at[j, 'sra']) + '\r\n'
else:
for j in range(0, 12):
file += str(j + 1) + ' 0\r\n'
i += 1
file += '\r\n'
file += '% ONE YEAR\r\n'
file += 's 300 cum 4.1 4.2\r\n'
file += 's 303 atend 300.1 300.2\r\n'
file += '\r\n'
file += 's ' + str(310) + ' WRITE\r\n'
file += '4.1 4.2\r\n'
file += 'p ' + str(310) + '\r\n'
file += '1 % Mode\r\n'
file += '0 % Suppress FNQ inputs\r\n'
file += "'" + str(insel_outputs_path) + "' % File name\r\n"
file += "'*' % Fortran format\r\n"
return file
@staticmethod
def demand(insel_outputs_path):
heating = []
cooling = []
with open(Path(insel_outputs_path).resolve()) as csv_file:
csv_reader = csv.reader(csv_file)
for line in csv_reader:
demand = str(line).replace("['", '').replace("']", '').split()
for i in range(0, 2):
if demand[i] != 'NaN':
aux = float(demand[i])*1000 # kWh to Wh
demand[i] = str(aux)
heating.append(demand[0])
cooling.append(demand[1])
monthly_heating = pd.DataFrame(heating, columns=['INSEL'])
monthly_cooling = pd.DataFrame(cooling, columns=['INSEL'])
return monthly_heating, monthly_cooling

109
main.py
View File

@ -16,21 +16,16 @@ from helpers import monthly_values as mv
from simplified_radiosity_algorithm import SimplifiedRadiosityAlgorithm
from imports.geometry_factory import GeometryFactory
from imports.weather_factory import WeatherFactory
from city_model_structure.city import City
from monthly_demand_calculation import MonthlyDemandCalculation
from helpers.enrich_city import EnrichCity
from imports.construction_factory import ConstructionFactory
from imports.usage_factory import UsageFactory
from exports.energy_building_exports_factory import EnergyBuildingsExportsFactory
from insel.monthly_demand_calculation import MonthlyDemandCalculation
parser = ArgumentParser(description='Monthly energy balance workflow v0.1.')
parser = ArgumentParser(description='Monthly energy balance workflow v1.0.')
required = parser.add_argument_group('required arguments')
parser.add_argument('--geometry_type', '-g', help='Geometry type {citygml}', default='citygml')
required.add_argument('--input_geometry_file', '-i', help='Input geometry file', required=True)
parser.add_argument('--use_pickle_file', '-p', help='Use pickle file instead of importing geometry file', default=False,
required=True)
parser.add_argument('--populated_step_in_pickle', '-ps', help='Physics and usage parameters already in pickle file',
default=False, required=True)
parser.add_argument('--weather_step_in_pickle', '-ws', help='Weather parameters already in pickle file',
default=False, required=True)
parser.add_argument('--use_cached_sra_file', '-u', help='Use sra files from cache, instead of freshly calculated sra '
'files', default=False)
required.add_argument('--project_folder', '-f', help='Project folder', required=True)
@ -45,45 +40,33 @@ keep_files = True
print('begin_time', datetime.datetime.now())
# Step 1: Initialize the city model
pickle_file = ''
if ast.literal_eval(args.use_pickle_file):
pickle_file = Path(args.input_geometry_file).resolve()
city = City.load(pickle_file)
else:
file = Path(args.input_geometry_file).resolve()
pickle_file = Path(str(file).replace('.gml', '.pickle'))
city = GeometryFactory(args.geometry_type, file).city
print(len(city.buildings))
for building in city.buildings:
file = Path(args.input_geometry_file).resolve()
city = GeometryFactory(args.geometry_type, file).city
for building in city.buildings:
volume = building.volume
if str(volume) == 'inf':
sys.stderr.write(f'Building {building.name} has geometry errors. It has been removed from the city\n')
city.remove_city_object(building)
city.save(pickle_file)
print('begin_populating_time', datetime.datetime.now())
# Step 2: Populate city adding thermal- and usage-related parameters
populated_step_in_pickle = ast.literal_eval(args.populated_step_in_pickle)
if populated_step_in_pickle:
populated_city = city
else:
populated_city = EnrichCity(city).enriched_city(construction_format='nrcan', usage_format='hft')
pickle_file = Path(str(pickle_file).replace('.pickle', '_populated.pickle'))
populated_city.save(pickle_file)
if populated_city.buildings is None:
print('No building to be calculated')
sys.exit()
for building in city.buildings:
building.year_of_construction = 2006
if building.function is None:
building.function = 'large office'
building.attic_heated = 0
building.basement_heated = 1
ConstructionFactory('nrel', city).enrich()
UsageFactory('comnet', city).enrich()
print('begin_weather_time', datetime.datetime.now())
# Step 3: Populate city adding climate-related parameters
weather_format = 'epw'
weather_step_in_pickle = ast.literal_eval(args.weather_step_in_pickle)
if not weather_step_in_pickle:
city.climate_reference_city = args.climate_reference_city
path = (Path(args.project_folder) / 'tmp').resolve()
city.climate_file = (path / f'{args.climate_reference_city}.cli').resolve()
WeatherFactory(weather_format, populated_city, file_name=args.weather_file_name).enrich()
for building in populated_city.buildings:
city.climate_reference_city = args.climate_reference_city
tmp_path = (Path(args.project_folder) / 'tmp').resolve()
city.climate_file = (tmp_path / f'{args.climate_reference_city}.cli').resolve()
WeatherFactory(weather_format, city, file_name=args.weather_file_name).enrich()
for building in city.buildings:
if cte.HOUR not in building.external_temperature:
print('No external temperature found')
sys.exit()
@ -92,15 +75,11 @@ if not weather_step_in_pickle:
building.external_temperature[cte.MONTH] = mv.MonthlyValues().\
get_mean_values(building.external_temperature[cte.HOUR][[weather_format]])
max_buildings_handled_by_sra = 500
for building in city.buildings:
for surface in building.surfaces:
surface.swr = 0.2
sra = SimplifiedRadiosityAlgorithm(city, Path(args.project_folder).resolve(), args.weather_file_name)
if ast.literal_eval(args.use_cached_sra_file):
sra.results()
sra.set_irradiance_surfaces(populated_city)
else:
max_buildings_handled_by_sra = 500
sra = SimplifiedRadiosityAlgorithm(city, Path(args.project_folder).resolve(), args.weather_file_name)
if ast.literal_eval(args.use_cached_sra_file):
sra.set_irradiance_surfaces(city)
else:
total_number_of_buildings = len(city.buildings)
if total_number_of_buildings > max_buildings_handled_by_sra:
radius = 80
@ -108,50 +87,44 @@ if not weather_step_in_pickle:
new_city = city.region(building.centroid, radius)
sra_new = SimplifiedRadiosityAlgorithm(new_city, Path(args.project_folder).resolve(), args.weather_file_name)
sra_new.call_sra(weather_format, keep_files=True)
sra_new.set_irradiance_surfaces(populated_city, building_name=building.name)
sra_new.set_irradiance_surfaces(city, building_name=building.name)
else:
sra.call_sra(weather_format, keep_files=keep_files)
sra.set_irradiance_surfaces(populated_city)
pickle_file = Path(str(pickle_file).replace('.pickle', '_weather.pickle'))
populated_city.save(pickle_file)
print('begin_user_assignment_time', datetime.datetime.now())
# Step 4: Assign user defined parameters
for building in populated_city.buildings:
building.attic_heated = 2
building.basement_heated = 0
sra.set_irradiance_surfaces(city)
print('begin_insel_time', datetime.datetime.now())
# Step 5: Demand calculation calling INSEL
MonthlyDemandCalculation(city, args.project_folder, weather_format).monthly_demand()
EnergyBuildingsExportsFactory('insel_monthly_energy_balance', city, tmp_path).export()
insel = MonthlyDemandCalculation(city, tmp_path, weather_format)
insel.run()
insel.results()
print('begin_write_results_time', datetime.datetime.now())
# Step 6: Print results
print_results = None
file = 'city name: ' + city.name + '\n'
for building in populated_city.buildings:
for building in city.buildings:
insel_file_name = building.name + '.insel'
building_results = building.heating[cte.MONTH].rename(columns={'INSEL': building.name})
heating_results = building.heating[cte.MONTH].rename(columns={'INSEL': f'{building.name} heating Wh'})
cooling_results = building.cooling[cte.MONTH].rename(columns={'INSEL': f'{building.name} cooling Wh'})
if print_results is None:
print_results = building_results
print_results = heating_results
else:
print_results = pd.concat([print_results, building_results], axis='columns')
print_results = pd.concat([print_results, heating_results], axis='columns')
print_results = pd.concat([print_results, cooling_results], axis='columns')
file += '\n'
file += 'name: ' + building.name + '\n'
file += 'year of construction: ' + building.year_of_construction + '\n'
file += 'year of construction: ' + str(building.year_of_construction) + '\n'
file += 'function: ' + building.function + '\n'
file += 'floor area: ' + str(building.thermal_zones[0].floor_area) + '\n'
file += 'floor area: ' + str(building.internal_zones[0].area) + '\n'
file += 'storeys: ' + str(building.storeys_above_ground) + '\n'
file += 'heated_volume: ' + str(building.volume) + '\n'
file += 'volume: ' + str(building.volume) + '\n'
full_path_results = Path(args.project_folder + '/outputs/heating_demand.csv').resolve()
full_path_results = Path(args.project_folder + '/outputs/demand.csv').resolve()
print_results.to_csv(full_path_results)
full_path_metadata = Path(args.project_folder + '/outputs/metadata.csv').resolve()
with open(full_path_metadata, 'w') as metadata_file:
metadata_file.write(file)
pickle_file = Path(str(pickle_file).replace('.pickle', '_demand.pickle'))
populated_city.save(pickle_file)
print('end_time', datetime.datetime.now())

View File

@ -1,181 +0,0 @@
"""
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 imports.geometry_factory import GeometryFactory
from populate import Populate
from imports.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:
weather_format = 'epw'
self._city_with_weather = self._get_citygml(use_pickle=use_pickle)
weather_path = (self._example_path / 'weather').resolve()
WeatherFactory(weather_format, self._city_with_weather, 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'][['epw']])
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(weather_format, 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):
weather_format = 'epw'
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.centroid, radius)
sra_file_name = 'SRA'
print('location', building.centroid)
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(weather_format, keep_files=True)
sra.set_irradiance_surfaces(self._city_with_cli, building_name=building_name)
return self._city_with_cli
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)