partial implementation of trnsys export

This commit is contained in:
Guille Gutierrez 2024-02-07 06:35:14 +01:00
parent 0015a3efd7
commit 39951a76a9
4 changed files with 89 additions and 47 deletions

View File

@ -359,6 +359,8 @@ class City:
Get city latitude in degrees
:return: None or float
"""
if self._latitude is None:
return self._get_location().climate_reference_city_latitude
return self._latitude
@latitude.setter
@ -376,6 +378,8 @@ class City:
Get city longitude in degrees
:return: None or float
"""
if self._longitude is None:
return self._get_location().climate_reference_city_longitude
return self._longitude
@longitude.setter

View File

@ -4,9 +4,18 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
import json
import math
from datetime import datetime
from pathlib import Path
from urllib.error import URLError
from urllib.request import urlopen
import pytz
from timezonefinder import TimezoneFinder
from hub.version import __version__
import hub.helpers.constants as cte
class Trnsys:
@ -18,6 +27,8 @@ class Trnsys:
self._city = city
self._path = path
self._buildings = self._city.buildings
self._tf = TimezoneFinder()
if target_buildings is not None:
buildings = []
for building in target_buildings:
@ -32,9 +43,9 @@ class Trnsys:
f.write('***************************************\n')
f.write('* Building descriptions file TRNSYS\n')
location = (
self._city.location.climate_reference_city_latitude, self._city.location.climate_reference_city_longitude
self._city.latitude, self._city.longitude
)
f.write(f'* Export: {self._city.location.city} {self._city.location.country} {location}')
f.write(f'* Export: {self._city.location.city} {self._city.location.country} {location}\n')
f.write(f'* For building: {building.name}')
if building.aliases is not None:
f.write(f' {building.aliases})')
@ -43,8 +54,19 @@ class Trnsys:
f.write(f'* Year build: {building.year_of_construction}\n')
f.write('***************************************\n')
@staticmethod
def _properties(f):
def _properties(self, f):
latitude = self._city.latitude
longitude = self._city.longitude
utc_offset = datetime.now(
pytz.timezone(self._tf.timezone_at(lng=longitude, lat=latitude))
).utcoffset().total_seconds()/60/60
elevation = 200
try:
elevation = json.loads(
urlopen(f'https://api.open-elevation.com/api/v1/lookup?locations={latitude},{longitude}').read()
)['results'][0]['elevation']
except URLError:
pass
f.write('***************************************\n')
f.write(f'* Properties\n')
f.write('***************************************\n')
@ -57,7 +79,7 @@ class Trnsys:
f.write(' KVERTICAL=5.76 : EVERTICAL=0.3\n')
f.write('* Radiance parameters\n')
f.write(' SCENE_ROTATION_ANGLE=0 : GROUND_IDS= : GROUND_REFLECTANCE=0.2 : SHADER_REFLECTANCE=0\n')
f.write(' CALC_MODE=RAD : LATITUDE=48 : LONGITUDE=-9.2 : TIME_ZONE=-15 : SITE_ELEVATION=200\n')
f.write(f' CALC_MODE=RAD : LATITUDE={latitude} : LONGITUDE={longitude} : TIME_ZONE={utc_offset} : SITE_ELEVATION={elevation}\n')
f.write(' AB=5 : AD=1000 : AS=20 : AR=300 : AA=0.1\n')
f.write(' LR=6 : ST=0.15 : SJ=1 : LW=0.004 : DJ=0 : DS=0.2 : DR=2 : DP=512\n')
f.write('* Comfort parameters\n')
@ -75,15 +97,27 @@ class Trnsys:
f.write(f'* Layers\n')
f.write('***************************************\n')
layers = {}
for thermal_zone in building.thermal_zones_from_internal_zones:
for thermal_boundary in thermal_zone.thermal_boundaries:
for layer in thermal_boundary.layers:
capacity = 0
conductivity = 0
density = 0
if layer.thermal_absorptance is not None:
capacity = layer.thermal_absorptance
if layer.conductivity is not None:
conductivity = layer.conductivity
if layer.density is not None:
density = layer.density
layers[layer.material_name] = {
'conductivity': layer.conductivity,
'capacity': '1', # todo: ask oriol about this
'density': layer.density,
'pert': '0', # todo: ask oriol about this
'penrt': '0', # todo: ask oriol about this
'conductivity': conductivity,
'capacity': capacity, # todo: transform units
'density': density,
'pert': '0',
'penrt': '0'
}
f.write('PROPERTIES\n')
for layer_name, values in layers.items():
@ -92,31 +126,41 @@ class Trnsys:
f.write(f'{attribute.upper()}=\t{value}\t')
f.write('\n')
@staticmethod
def _inputs(f):
f.write('***************************************\n')
f.write(f'* Inputs\n')
f.write('***************************************\n')
f.write('INPUTS TGROUND TBOUNDARY SHADE_CLOSE SHADE_OPEN MAX_ISHADE MAX_ESHADE\n')
f.write('INPUTS_DESCRIPTION\n')
f.write('TGROUND : C : Ground Temperature (boundary temperature used for floors adjacent to the ground)\n')
f.write('TBOUNDARY : C : Boundary Temperature (boundary temperature used for boundary floors, walls, ceilings)\n')
f.write('SHADE_CLOSE : kJ/hr.m^2 : threshold of total radiation on facade where shading device is activated\n')
f.write('SHADE_OPEN : kJ/hr.m^2 : threshold of total radiation on facade where shading device is deactivated\n')
f.write('MAX_ISHADE : any : max shading factor of internal shading\n')
f.write('MAX_ESHADE : any : max shading factor of external shading\n')
@staticmethod
def _geometry_information(f, building):
f.write('[Geometry]\n')
f.write(f'Length: {building.upper_corner[0] - building.lower_corner[0]}\n')
f.write(f'Width: {building.upper_corner[1] - building.lower_corner[1]}\n')
f.write(f'Height: {building.upper_corner[2] - building.lower_corner[2]}\n')
@staticmethod
def _wall_construction(f, building):
basic_thermal_boundary = building.walls[0].associated_thermal_boundaries[0]
f.write('[Wall Construction]\n')
f.write(f'Wall Type: Multi-Layered Wall\n')
f.write(f'Layers: {len(basic_thermal_boundary.layers)}')
for i, layer in enumerate(basic_thermal_boundary.layers):
f.write(f'Layer {i}: {layer.material_name}\n')
f.write(f'Thickness: {layer.thickness}m\n')
@staticmethod
def _wall_information(f, building):
f.write('[Wall Section]\n')
f.write(f'Material: {building.upper_corner[0] - building.lower_corner[0]}\n')
f.write(f'Width: {building.upper_corner[1] - building.lower_corner[1]}\n')
f.write(f'Height: {building.upper_corner[2] - building.lower_corner[2]}\n')
def _schedules(f, building):
f.write('***************************************\n')
f.write(f'* Schedules\n')
f.write('***************************************\n')
for thermal_zone in building.thermal_zones_from_internal_zones:
for usage in thermal_zone.usages:
for schedule in usage.occupancy.occupancy_schedules:
if schedule.time_step is cte.HOUR:
for day_type in schedule.day_types:
f.write(f'SCHEDULE {day_type.upper()}\n')
hours = 'HOURS= '
values = 'VALUES= '
previous = math.inf
for hour, value in enumerate(schedule.values):
if previous != value:
hours = f'{hours} {hour}.000'
values = f'{values} {value}'
previous = value
f.write(f'{hours} 24.0\n')
f.write(f'{values} {schedule.values[0]}\n')
def export(self):
print("export")
@ -125,11 +169,9 @@ class Trnsys:
with open(path, 'w', encoding='utf-8') as f:
print(path)
self._header(f, building)
Trnsys._properties(f)
self._properties(f)
Trnsys._types(f, building)
Trnsys._inputs(f)
Trnsys._schedules(f, building)
"""
self._building_information(f, building)
Trnsys._geometry_information(f, building)
Trnsys._wall_information(f, building)
"""

View File

@ -23,4 +23,5 @@ geopandas
triangle
psycopg2-binary
Pillow
pathlib
pathlib
timezonefinder

View File

@ -162,12 +162,7 @@ class TestExports(TestCase):
function_to_hub=Dictionaries().montreal_function_to_hub_function).city
self.assertIsNotNone(city, 'city is none')
EnergyBuildingsExportsFactory('trnsys', city, self._output_path).export()
ConstructionFactory('nrcan', city).enrich()
EnergyBuildingsExportsFactory('idf', city, self._output_path).export()
UsageFactory('nrcan', city).enrich()
WeatherFactory('epw', city).enrich()
try:
EnergyBuildingsExportsFactory('trnsys', city, self._output_path).export()
except Exception:
self.fail("Trnsys ExportsFactory raised ExceptionType unexpectedly!")
EnergyBuildingsExportsFactory('trnsys', city, self._output_path).export()