Source code for ladybug.stat
from .location import Location
import os
import re
import codecs
import platform
[docs]class Stat(object):
"""Import data from a local .stat file.
args:
file_path: Local file address to a .stat file.
properties:
location
ashrae_climate_zone
koppen_climate_zone
monthly_tau_beam
monthly_tau_diffuse
"""
def __init__(self, file_path=None):
"""Initalize the class."""
self.file_path = file_path
self._is_data_loaded = False
self._header = None # epw header
@property
def file_path(self):
"""Get or set path to stat file."""
return self._file_path
@property
def folder(self):
"""Get stat file folder."""
return self._folder
@property
def file_name(self):
"""Get stat file name."""
return self._file_name
@file_path.setter
def file_path(self, stat_file_path):
self._file_path = os.path.normpath(stat_file_path)
if not os.path.isfile(self._file_path):
raise ValueError(
'Cannot find an stat file at {}'.format(self._file_path))
if not stat_file_path.lower().endswith('stat'):
raise TypeError(stat_file_path + ' is not an .stat file.')
self._folder, self._file_name = os.path.split(self.file_path)
@property
def is_data_loaded(self):
"""Return True if data is loaded."""
return self._is_data_loaded
# TODO: import heating + cooling design temperatures
# TODO: import hot, cold and typical weeks
[docs] def import_data(self):
"""Import data from a stat file.
"""
try:
iron_python = True if platform.python_implementation() == 'IronPython' \
else False
except ValueError as e:
# older version of IronPython failse to parse version correctly
# failed to parse IronPython sys.version: '2.7.5 (IronPython 2.7.5 (2.7.5.0)
# on .NET 4.0.30319.42000 (64-bit))'
if 'IronPython' in str(e):
iron_python = True
if iron_python:
statwin = codecs.open(self.file_path, 'r')
else:
statwin = codecs.open(self.file_path, 'r', encoding='utf-8', errors='ignore')
try:
line = statwin.readline()
# import header with location
self._header = [line] + [statwin.readline() for i in range(9)]
except Exception as e:
import traceback
raise Exception('{}\n{}'.format(e, traceback.format_exc()))
else:
# import location data
loc_name = self._header[2].strip().replace('Location -- ', '')
if ' - ' in loc_name:
city = ' '.join(loc_name.split(' - ')[:-1])
else:
# for US stat files it is full name separated by spaces
# Chicago Ohare Intl Ap IL USA
city = ' '.join(loc_name.split()[:-2])
country = loc_name.split(' ')[-1]
source = self._header[6].strip().replace('Data Source -- ', '')
station_id = self._header[8].strip().replace('WMO Station ', '')
if iron_python:
# IronPython
coord_pattern = re.compile(r"{([NSEW])(\s*\d*)deg(\s*\d*)'}")
matches = coord_pattern.findall(self._header[3].replace('\xb0', 'deg'))
else:
# CPython
coord_pattern = re.compile(r"{([NSEW])(\s*\d*) (\s*\d*)'}")
matches = coord_pattern.findall(self._header[3])
lat_sign = -1 if matches[0][0] == 'S' else 1
latitude = lat_sign * (float(matches[0][1]) + (float(matches[0][2]) / 60))
lon_sign = -1 if matches[1][0] == 'W' else 1
longitude = lon_sign * (float(matches[1][1]) + (float(matches[1][2]) / 60))
tz_pattern = re.compile(r"{GMT\s*(\S*)\s*Hours}")
time_zone = float(tz_pattern.findall(self._header[3])[0])
elev_pattern = re.compile(r"Elevation\s*[-]*\s*(\d*)m\s*(\S*)")
elev_matches = elev_pattern.findall(self._header[4])
elev_sign = -1 if elev_matches[0][-1].lower() == 'below' else 1
elevation = elev_sign * float(elev_matches[0][0])
self._location = Location()
self._location.city = city
self._location.country = country
self._location.source = source
self._location.station_id = station_id
self._location.latitude = latitude
self._location.longitude = longitude
self._location.time_zone = time_zone
self._location.elevation = elevation
# defaults in case the climate is unclassifiable
self._ashrae_climate_zone = None
self._koppen_climate_zone = None
# move through the document and pull out the climate zone and tau values
for line in statwin:
if 'taub (beam)' in line:
taub_raw = line.replace('taub (beam)', '').strip().split('\t')
self._monthly_tau_beam = [float(i) if 'N' not in i
else None for i in taub_raw]
elif 'taud (diffuse)' in line:
taud_raw = line.replace('taud (diffuse)', '').strip().split('\t')
self._monthly_tau_diffuse = [float(i) if 'N' not in i
else None for i in taud_raw]
elif 'Climate type' in line and 'ASHRAE' in line:
self._ashrae_climate_zone = line.split('"')[1]
elif 'Climate type' in line:
self._koppen_climate_zone = line.split('"')[1]
finally:
statwin.close()
self._is_data_loaded = True
@property
def header(self):
"""Return stat file header."""
if not self.is_data_loaded:
self.import_data()
return self._header
@property
def location(self):
"""Return ladybug location object."""
if not self.is_data_loaded:
self.import_data()
return self._location
@property
def ashrae_climate_zone(self):
"""Return a text string indicating the ASHRAE climate zone.
ASHRAE climate zones are frequently used to make suggestions for
heating and cooling systems and correspond to recommendations for
insulation levels of a building.
"""
if not self.is_data_loaded:
self.import_data()
return self._ashrae_climate_zone
@property
def koppen_climate_zone(self):
"""Return a text string indicating the Koppen climate zone.
The Koppen climate classification is the most widely used climate
classification system and combines average annual and monthly
temperatures, precipitation, and the seasonality of precipitation.
"""
if not self.is_data_loaded:
self.import_data()
return self._koppen_climate_zone
@property
def monthly_tau_beam(self):
"""Return a list of 12 float values for monthly beam optical depth.
These values can be used to generate ASHRAE Revised Clear Skies, which
are intended to determine peak solar load and sizing parmeters for
HVAC systems.
"""
if not self.is_data_loaded:
self.import_data()
return self._monthly_tau_beam
@property
def monthly_tau_diffuse(self):
"""Return a list of 12 float values for monthly diffuse optical depth.
These values can be used to generate ASHRAE Revised Clear Skies, which
are intended to determine peak solar load and sizing parmeters for
HVAC systems.
"""
if not self.is_data_loaded:
self.import_data()
return self._monthly_tau_diffuse
[docs] def ToString(self):
"""Overwrite .NET ToString."""
return self.__repr__()
def __repr__(self):
"""stat file representation."""
return "STAT [%s]" % self.location.city