Skip to content

Commit

Permalink
fix(epw): Update design day fields for ASHRAE 2021
Browse files Browse the repository at this point in the history
Resolves #604
  • Loading branch information
chriswmackey committed Oct 31, 2024
1 parent becb52f commit a659ce8
Show file tree
Hide file tree
Showing 4 changed files with 8,847 additions and 19 deletions.
5 changes: 3 additions & 2 deletions ladybug/designday.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,11 @@ class DesignDay(object):
'CustomDay1', 'CustomDay2')

# keys denoting the values from which design days are derived
# these keys and their order com from Climate Design Data of ASHRAE Handbook
# these keys and their order come from Climate Design Data of ASHRAE Handbook
# https://ashrae-meteo.info/
HEATING_KEYS = ('Month', 'DB996', 'DB990', 'DP996', 'HR_DP996', 'DB_DP996',
'DP990', 'HR_DP990', 'DB_DP990', 'WS004c', 'DB_WS004c',
'WS010c', 'DB_WS010c', 'WS_DB996', 'WD_DB996')
'WS010c', 'DB_WS010c', 'WS_DB996', 'WD_DB996', 'WSF')
COOLING_KEYS = ('Month', 'DBR', 'DB004', 'WB_DB004', 'DB010', 'WB_DB010',
'DB020', 'WB_DB020', 'WB004', 'DB_WB004', 'WB010', 'DB_WB010',
'WB020', 'DB_WB020', 'WS_DB004', 'WD_DB004', 'DP004',
Expand Down
69 changes: 52 additions & 17 deletions ladybug/epw.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ class EPW(object):
* sky_temperature
"""
__slots__ = ('_file_path', '_is_header_loaded', '_is_data_loaded', '_is_ip',
'_data', '_metadata', '_location',
'_data', '_metadata', '_location', '_is_2009_ashrae',
'_heating_dict', '_cooling_dict', '_extremes_dict',
'_extreme_hot_weeks', '_extreme_cold_weeks', '_typical_weeks',
'_monthly_ground_temps', '_is_leap_year', 'daylight_savings_start',
Expand All @@ -126,6 +126,7 @@ def __init__(self, file_path):
# placeholders for the EPW data that will be imported
self._data = []
self._metadata = {}
self._is_2009_ashrae = False
self._heating_dict = {}
self._cooling_dict = {}
self._extremes_dict = {}
Expand Down Expand Up @@ -326,6 +327,8 @@ def from_dict(cls, data):

# Set all of the header properties if they exist in the dictionary.
epw_obj._metadata = data['metadata']
epw_obj._is_2009_ashrae = data['is_2009_ashrae'] \
if 'is_2009_ashrae' in data else False
epw_obj.heating_design_condition_dictionary = data['heating_dict']
epw_obj.cooling_design_condition_dictionary = data['cooling_dict']
epw_obj.extreme_design_condition_dictionary = data['extremes_dict']
Expand Down Expand Up @@ -441,18 +444,34 @@ def _import_location(self, line):
def _import_header(self, header_lines):
"""Set EPW design days, typical weeks, and ground temperatures from header lines.
"""
# parse the heating, cooling and extreme design conditions.
# parse the heating, cooling and extreme design conditions.
dday_data = header_lines[1].strip().split(',')
if len(dday_data) >= 2 and int(dday_data[1]) == 1:
if dday_data[4] == 'Heating':
for key, val in zip(DesignDay.HEATING_KEYS, dday_data[5:20]):
self._heating_dict[key] = val
if dday_data[20] == 'Cooling':
for key, val in zip(DesignDay.COOLING_KEYS, dday_data[21:53]):
self._cooling_dict[key] = val
if dday_data[53] == 'Extremes':
for key, val in zip(DesignDay.EXTREME_KEYS, dday_data[54:70]):
self._extremes_dict[key] = val
if '2009' in dday_data[2]: # parse using ASHRAE 2009 standard
self._is_2009_ashrae = True
if dday_data[4] == 'Heating':
for key, val in zip(DesignDay.HEATING_KEYS, dday_data[5:20]):
self._heating_dict[key] = val
if dday_data[20] == 'Cooling':
for key, val in zip(DesignDay.COOLING_KEYS, dday_data[21:53]):
self._cooling_dict[key] = val
if dday_data[53] == 'Extremes':
for key, val in zip(DesignDay.EXTREME_KEYS, dday_data[54:70]):
self._extremes_dict[key] = val
else: # parse using the ASHRAE 2021 standard
if dday_data[4] == 'Heating':
for key, val in zip(DesignDay.HEATING_KEYS, dday_data[5:21]):
self._heating_dict[key] = val
if dday_data[21] == 'Cooling':
for key, val in zip(DesignDay.COOLING_KEYS, dday_data[22:54]):
if key == 'Hrs_8-4_&_DB':
key = 'WBmax'
self._cooling_dict[key] = val
if dday_data[54] == 'Extremes':
ext_keys = list(DesignDay.EXTREME_KEYS)
ext_keys.pop(3) # ASHRAE moved this key
for key, val in zip(ext_keys, dday_data[55:71]):
self._extremes_dict[key] = val

# parse typical and extreme periods into analysis periods.
week_data = header_lines[2].split(',')
Expand Down Expand Up @@ -780,17 +799,20 @@ def _des_dict_check(self, des_dict, req_keys, cond_name):
"""Check if an input design condition dictionary is acceptable."""
assert isinstance(des_dict, dict), '{}' \
' must be a dictionary. Got {}.'.format(cond_name, type(des_dict))
if bool(des_dict):
optional_keys = ('Hrs_8-4_&_DB', 'WSF', 'WBmax')
if des_dict:
input_keys = list(des_dict.keys())
for key in req_keys:
if key in optional_keys:
continue
assert key in input_keys, 'Required key "{}" was not found in ' \
'{}'.format(key, cond_name)

def _weeks_check(self, data, week_type):
"""Check if input for the typical/extreme weeks of the header is correct."""
assert isinstance(data, dict), '{}' \
' must be an OrderedDict. Got {}.'.format(week_type, type(data))
if bool(data):
if data:
for val in data.values():
assert isinstance(val, AnalysisPeriod), '{} dictionary must contain' \
' AnalysisPeriod objects. Got {}.'.format(week_type, type(val))
Expand All @@ -810,11 +832,23 @@ def header(self):
summer_found = bool(self._cooling_dict)
extreme_found = bool(self._extremes_dict)
if winter_found and summer_found and extreme_found:
des_str = 'DESIGN CONDITIONS,1,Climate Design Data 2009 ASHRAE Handbook,,'
if self._is_2009_ashrae:
des_str = 'DESIGN CONDITIONS,1,Climate Design Data 2009 ' \
'ASHRAE Handbook,,'
h_keys, c_keys = list(DesignDay.HEATING_KEYS), DesignDay.COOLING_KEYS
h_keys.pop(-1)
ext_keys = DesignDay.EXTREME_KEYS
else:
des_str = 'DESIGN CONDITIONS,1,2021 ASHRAE Handbook -- Fundamentals - ' \
'Chapter 14 Climatic Design Information,,'
h_keys, c_keys = DesignDay.HEATING_KEYS, list(DesignDay.COOLING_KEYS)
c_keys[-1] = 'WBmax'
ext_keys = list(DesignDay.EXTREME_KEYS)
ext_keys.pop(3)
des_str = des_str + 'Heating,{},Cooling,{},Extremes,{}\n'.format(
','.join([self._heating_dict[key] for key in DesignDay.HEATING_KEYS]),
','.join([self._cooling_dict[key] for key in DesignDay.COOLING_KEYS]),
','.join([self._extremes_dict[key] for key in DesignDay.EXTREME_KEYS]))
','.join([self._heating_dict[key] for key in h_keys]),
','.join([self._cooling_dict[key] for key in c_keys]),
','.join([self._extremes_dict[key] for key in ext_keys]))
else:
des_str = 'DESIGN CONDITIONS,0\n'
weeks = []
Expand Down Expand Up @@ -1684,6 +1718,7 @@ def dictify_dict(base_dict):
'extreme_cold_weeks': cold_wks,
'typical_weeks': typ_wks,
"monthly_ground_temps": grnd_temps,
"is_2009_ashrae": self._is_2009_ashrae,
"is_ip": self._is_ip,
"is_leap_year": self.is_leap_year,
"daylight_savings_start": self.daylight_savings_start,
Expand Down
Loading

0 comments on commit a659ce8

Please sign in to comment.