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 # 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 ##### External software
+ INSEL 8 (https://insel4d.ca/en/download.html) + 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. 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 ## installation
##### Linux / Mac ##### Linux / Mac
@ -81,5 +62,3 @@ $ python main.py
``` ```
c:\> python.exe main.py c:\> python.exe main.py
``` ```

View File

@ -1,60 +1,18 @@
import os import os
from pathlib import Path from pathlib import Path
from abc import ABC
class Insel: class Insel(ABC):
def __init__(self, path, name, new_content="", mode=1, keep_files=False): def __init__(self, path):
self._path = path self._path = path
self._name = name
self._full_path = None
self._content = None
self._results = 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): def run(self):
output = os.system('insel ' + str(self.full_path)) paths = sorted(Path(self._path).glob('*.insel'))
# todo: catch errors from INSEL for file in paths:
if not self._keep_files: os.system('insel ' + str(file))
os.remove(self.full_path)
@property @property
def results(self): 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 from pathlib import Path
import pandas as pd import pandas as pd
import sys import sys
import csv
from insel.templates.monthly_energy_balance import MonthlyEnergyBalance as templates
from insel.insel import Insel from insel.insel import Insel
class MonthlyDemandCalculation: class MonthlyDemandCalculation(Insel):
def __init__(self, city, main_path, weather_format): def __init__(self, city, main_path, weather_format):
super().__init__(main_path)
self._city = city self._city = city
self._main_path = main_path
self._weather_format = weather_format self._weather_format = weather_format
def monthly_demand(self): def results(self):
for building in self._city.buildings: 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) full_path_out.parent.mkdir(parents=True, exist_ok=True)
insel_file_name = building.name + '.insel'
try: try:
content = templates.generate_meb_template(building, full_path_out, self._weather_format) building.heating['month'], building.cooling['month'] = self._demand(full_path_out)
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)
heating_year = 0 heating_year = 0
for value in building.heating['month']['INSEL']: for value in building.heating['month']['INSEL']:
if value == 'NaN': if value == 'NaN':
@ -47,3 +44,21 @@ class MonthlyDemandCalculation:
print(sys.exc_info()[1]) print(sys.exc_info()[1])
print('Building ' + building.name + ' could not be processed') print('Building ' + building.name + ' could not be processed')
continue 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

93
main.py
View File

@ -16,21 +16,16 @@ from helpers import monthly_values as mv
from simplified_radiosity_algorithm import SimplifiedRadiosityAlgorithm from simplified_radiosity_algorithm import SimplifiedRadiosityAlgorithm
from imports.geometry_factory import GeometryFactory from imports.geometry_factory import GeometryFactory
from imports.weather_factory import WeatherFactory from imports.weather_factory import WeatherFactory
from city_model_structure.city import City from imports.construction_factory import ConstructionFactory
from monthly_demand_calculation import MonthlyDemandCalculation from imports.usage_factory import UsageFactory
from helpers.enrich_city import EnrichCity 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') required = parser.add_argument_group('required arguments')
parser.add_argument('--geometry_type', '-g', help='Geometry type {citygml}', default='citygml') 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) 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 ' parser.add_argument('--use_cached_sra_file', '-u', help='Use sra files from cache, instead of freshly calculated sra '
'files', default=False) 'files', default=False)
required.add_argument('--project_folder', '-f', help='Project folder', required=True) required.add_argument('--project_folder', '-f', help='Project folder', required=True)
@ -45,45 +40,33 @@ keep_files = True
print('begin_time', datetime.datetime.now()) print('begin_time', datetime.datetime.now())
# Step 1: Initialize the city model # 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() file = Path(args.input_geometry_file).resolve()
pickle_file = Path(str(file).replace('.gml', '.pickle'))
city = GeometryFactory(args.geometry_type, file).city city = GeometryFactory(args.geometry_type, file).city
print(len(city.buildings))
for building in city.buildings: for building in city.buildings:
volume = building.volume volume = building.volume
if str(volume) == 'inf': if str(volume) == 'inf':
sys.stderr.write(f'Building {building.name} has geometry errors. It has been removed from the city\n') sys.stderr.write(f'Building {building.name} has geometry errors. It has been removed from the city\n')
city.remove_city_object(building) city.remove_city_object(building)
city.save(pickle_file)
print('begin_populating_time', datetime.datetime.now()) print('begin_populating_time', datetime.datetime.now())
# Step 2: Populate city adding thermal- and usage-related parameters # Step 2: Populate city adding thermal- and usage-related parameters
populated_step_in_pickle = ast.literal_eval(args.populated_step_in_pickle) for building in city.buildings:
if populated_step_in_pickle: building.year_of_construction = 2006
populated_city = city if building.function is None:
else: building.function = 'large office'
populated_city = EnrichCity(city).enriched_city(construction_format='nrcan', usage_format='hft') building.attic_heated = 0
pickle_file = Path(str(pickle_file).replace('.pickle', '_populated.pickle')) building.basement_heated = 1
populated_city.save(pickle_file) ConstructionFactory('nrel', city).enrich()
if populated_city.buildings is None: UsageFactory('comnet', city).enrich()
print('No building to be calculated')
sys.exit()
print('begin_weather_time', datetime.datetime.now()) print('begin_weather_time', datetime.datetime.now())
# Step 3: Populate city adding climate-related parameters # Step 3: Populate city adding climate-related parameters
weather_format = 'epw' 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 city.climate_reference_city = args.climate_reference_city
path = (Path(args.project_folder) / 'tmp').resolve() tmp_path = (Path(args.project_folder) / 'tmp').resolve()
city.climate_file = (path / f'{args.climate_reference_city}.cli').resolve() city.climate_file = (tmp_path / f'{args.climate_reference_city}.cli').resolve()
WeatherFactory(weather_format, populated_city, file_name=args.weather_file_name).enrich() WeatherFactory(weather_format, city, file_name=args.weather_file_name).enrich()
for building in populated_city.buildings: for building in city.buildings:
if cte.HOUR not in building.external_temperature: if cte.HOUR not in building.external_temperature:
print('No external temperature found') print('No external temperature found')
sys.exit() sys.exit()
@ -93,13 +76,9 @@ if not weather_step_in_pickle:
get_mean_values(building.external_temperature[cte.HOUR][[weather_format]]) get_mean_values(building.external_temperature[cte.HOUR][[weather_format]])
max_buildings_handled_by_sra = 500 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) sra = SimplifiedRadiosityAlgorithm(city, Path(args.project_folder).resolve(), args.weather_file_name)
if ast.literal_eval(args.use_cached_sra_file): if ast.literal_eval(args.use_cached_sra_file):
sra.results() sra.set_irradiance_surfaces(city)
sra.set_irradiance_surfaces(populated_city)
else: else:
total_number_of_buildings = len(city.buildings) total_number_of_buildings = len(city.buildings)
if total_number_of_buildings > max_buildings_handled_by_sra: if total_number_of_buildings > max_buildings_handled_by_sra:
@ -108,50 +87,44 @@ if not weather_step_in_pickle:
new_city = city.region(building.centroid, radius) new_city = city.region(building.centroid, radius)
sra_new = SimplifiedRadiosityAlgorithm(new_city, Path(args.project_folder).resolve(), args.weather_file_name) 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.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: else:
sra.call_sra(weather_format, keep_files=keep_files) sra.call_sra(weather_format, keep_files=keep_files)
sra.set_irradiance_surfaces(populated_city) sra.set_irradiance_surfaces(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
print('begin_insel_time', datetime.datetime.now()) print('begin_insel_time', datetime.datetime.now())
# Step 5: Demand calculation calling INSEL # 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()) print('begin_write_results_time', datetime.datetime.now())
# Step 6: Print results # Step 6: Print results
print_results = None print_results = None
file = 'city name: ' + city.name + '\n' file = 'city name: ' + city.name + '\n'
for building in populated_city.buildings: for building in city.buildings:
insel_file_name = building.name + '.insel' 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: if print_results is None:
print_results = building_results print_results = heating_results
else: 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 += '\n'
file += 'name: ' + building.name + '\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 += '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 += 'storeys: ' + str(building.storeys_above_ground) + '\n'
file += 'heated_volume: ' + str(building.volume) + '\n' file += 'heated_volume: ' + str(building.volume) + '\n'
file += '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) print_results.to_csv(full_path_results)
full_path_metadata = Path(args.project_folder + '/outputs/metadata.csv').resolve() full_path_metadata = Path(args.project_folder + '/outputs/metadata.csv').resolve()
with open(full_path_metadata, 'w') as metadata_file: with open(full_path_metadata, 'w') as metadata_file:
metadata_file.write(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()) 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)