Skip to content

Commit

Permalink
fix(designday): Add full support for ASHRAETau2017 in design days
Browse files Browse the repository at this point in the history
  • Loading branch information
chriswmackey committed Mar 1, 2024
1 parent 333c799 commit d66225c
Show file tree
Hide file tree
Showing 5 changed files with 3,438 additions and 25 deletions.
58 changes: 41 additions & 17 deletions ladybug/designday.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,10 +205,11 @@ def from_idf(cls, idf_string, location):
if sky_model == 'ASHRAEClearSky':
sky_clr = float(ep_fields[26]) if len(ep_fields) > 26 else 0
sky_condition = ASHRAEClearSky(date_obj, sky_clr, dl_save)
elif sky_model == 'ASHRAETau':
elif sky_model in ('ASHRAETau', 'ASHRAETau2017'):
use_2017 = True if sky_model.endswith('2017') else False
t_b = float(ep_fields[24]) if len(ep_fields) > 24 else 0
t_d = float(ep_fields[25]) if len(ep_fields) > 25 else 0
sky_condition = ASHRAETau(date_obj, t_b, t_d, dl_save)
sky_condition = ASHRAETau(date_obj, t_b, t_d, use_2017, dl_save)
else:
sky_condition = _SkyCondition(date_obj, dl_save)
if sky_model == 'Schedule':
Expand Down Expand Up @@ -241,8 +242,7 @@ def from_design_day_properties(cls, name, day_type, location, date,
pressure: Barometric pressure in Pa.
wind_speed: Wind speed over the design day in m/s.
wind_dir: Wind direction over the design day in degrees.
sky_model: Type of solar model to use. Choose from:
ASHRAEClearSky, ASHRAETau
sky_model: Type of solar model to use. Choose from ASHRAEClearSky, ASHRAETau.
sky_properties: A list of properties describing the sky above.
For ASHRAEClearSky this is a single value for clearness
For ASHRAETau, this is the tau_beam and tau_diffuse
Expand All @@ -253,8 +253,10 @@ def from_design_day_properties(cls, name, day_type, location, date,
wind_condition = WindCondition(wind_speed, wind_dir)
if sky_model == 'ASHRAEClearSky':
sky_condition = ASHRAEClearSky(date, sky_properties[0])
elif sky_model == 'ASHRAETau':
sky_condition = ASHRAETau(date, sky_properties[0], sky_properties[-1])
elif sky_model in ('ASHRAETau', 'ASHRAETau2017'):
use_2017 = True if sky_model.endswith('2017') else False
sky_condition = ASHRAETau(
date, sky_properties[0], sky_properties[-1], use_2017)
return cls(name, day_type, location, dry_bulb_condition,
humidity_condition, wind_condition, sky_condition)

Expand Down Expand Up @@ -544,7 +546,7 @@ def to_idf(self):
if isinstance(self.sky_condition, ASHRAEClearSky):
ep_vals[25] = self.sky_condition.clearness
if isinstance(self.sky_condition, ASHRAETau):
ep_vals[20] = 'ASHRAETau'
ep_vals[20] = 'ASHRAETau2017' if self.sky_condition.use_2017 else 'ASHRAETau'
ep_vals[23] = self.sky_condition.tau_b
ep_vals[24] = self.sky_condition._tau_d
ep_vals.pop()
Expand Down Expand Up @@ -1363,30 +1365,36 @@ class ASHRAETau(_SkyCondition):
day occurs.
tau_b: Value for the beam optical depths. Typically found in .stat files.
tau_d: Value for the diffuse optical depth. Typically found in .stat files.
use_2017: A boolean to indicate whether the version of the ASHRAE Tau
model that should be the revised version published in 2017 (True)
or the original one published in 2009 (False). (Default: False).
daylight_savings: Boolean to indicate whether daylight savings
time is active. Default: False
time is active. (Default: False).
Properties:
* date
* tau_b
* tau_d
* use_2017
* daylight_savings
* hourly_sky_cover
"""
__slots__ = ('_tau_b', '_tau_d')
__slots__ = ('_tau_b', '_tau_d', '_use_2017')

def __init__(self, date, tau_b, tau_d, daylight_savings=False):
def __init__(self, date, tau_b, tau_d, use_2017=False, daylight_savings=False):
_SkyCondition.__init__(self, date, daylight_savings)
self.tau_b = tau_b
self.tau_d = tau_d
self.use_2017 = use_2017

@classmethod
def from_analysis_period(cls, analysis_period, tau_b, tau_d, daylight_savings=False):
def from_analysis_period(cls, analysis_period, tau_b, tau_d, use_2017=False,
daylight_savings=False):
""""Initialize a ASHRAETau sky condition from an analysis_period"""
cls._check_analysis_period(analysis_period)
st_dt = analysis_period.st_time
return cls(Date(st_dt.month, st_dt.day, st_dt.leap_year), tau_b, tau_d,
daylight_savings)
return cls(Date(st_dt.month, st_dt.day, st_dt.leap_year),
tau_b, tau_d, use_2017, daylight_savings)

@classmethod
def from_dict(cls, data):
Expand All @@ -1402,6 +1410,7 @@ def from_dict(cls, data):
"date": [7, 21],
"tau_b": 0.0, # float
"tau_d": 0.0, # float
"use_2017": True, # boolean for whether the 2017 model is used
"daylight_savings": False # bool
}
"""
Expand All @@ -1411,10 +1420,12 @@ def from_dict(cls, data):
assert key in data, 'Required key "{}" is missing!'.format(key)

# assign defaults for optional keys
use_2017 = data['use_2017'] if 'use_2017' in data else False
dl_save = data['daylight_savings'] if 'daylight_savings' \
in data else False

return cls(Date.from_array(data['date']), data['tau_b'], data['tau_d'], dl_save)
return cls(Date.from_array(data['date']),
data['tau_b'], data['tau_d'], use_2017, dl_save)

@property
def tau_b(self):
Expand All @@ -1438,6 +1449,16 @@ def tau_d(self, data):
' number. Got {}'.format(type(data))
self._tau_d = data

@property
def use_2017(self):
"""Boolean for whether the version of the 2017 version of the ASHRAE Tau is used.
"""
return self._use_2017

@use_2017.setter
def use_2017(self, value):
self._use_2017 = bool(value)

def radiation_values(self, location, timestep=1):
"""Gat arrays of direct, diffuse, and global radiation at each timestep."""
# create sunpath and get altitude at every timestep of the design day
Expand All @@ -1448,7 +1469,7 @@ def radiation_values(self, location, timestep=1):
sun = sp.calculate_sun_from_date_time(t_date)
altitudes.append(sun.altitude)
dir_norm, diff_horiz = ashrae_revised_clear_sky(
altitudes, self._tau_b, self._tau_d)
altitudes, self._tau_b, self._tau_d, self._use_2017)
glob_horiz = [dhr + dnr * math.sin(math.radians(alt)) for
alt, dnr, dhr in zip(altitudes, dir_norm, diff_horiz)]
return dir_norm, diff_horiz, glob_horiz
Expand All @@ -1460,15 +1481,18 @@ def to_dict(self):
'date': self.date.to_array(),
'tau_b': self.tau_b,
'tau_d': self.tau_d,
'use_2017': self.use_2017,
'daylight_savings': self.daylight_savings
}

def __copy__(self):
return ASHRAETau(self._date, self._tau_b, self._tau_d, self._daylight_savings)
return ASHRAETau(self._date, self._tau_b, self._tau_d, self._use_2017,
self._daylight_savings)

def __key(self):
"""A tuple based on the object properties, useful for hashing."""
return (hash(self._date), self._tau_b, self._tau_d, self._daylight_savings)
return (hash(self._date), self._tau_b, self._tau_d, self._use_2017,
self._daylight_savings)

def __hash__(self):
return hash(self.__key())
Expand Down
2 changes: 1 addition & 1 deletion ladybug/skymodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ def ashrae_revised_clear_sky(altitudes, tb, td, use_2017_model=False):
- dir_norm_rad: A list of direct normal radiation values for each
of the connected altitudes in W/m2.
- dif_horiz_rad: A list of diffuse horizontall radiation values for each
- dif_horiz_rad: A list of diffuse horizontally radiation values for each
of the connected altitudes in W/m2.
"""
dir_norm_rad = []
Expand Down
20 changes: 13 additions & 7 deletions ladybug/wea.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ def from_epw_file(cls, epw_file, timestep=1):
return cls(epw.location, direct_normal, diffuse_horizontal)

@classmethod
def from_stat_file(cls, statfile, timestep=1, is_leap_year=False):
def from_stat_file(cls, statfile, timestep=1, is_leap_year=False, use_2017=False):
"""Create an ASHRAE Revised Clear Sky Wea object from data in .stat file.
The .stat file must have monthly sky optical depths within it in order to
Expand All @@ -336,6 +336,9 @@ def from_stat_file(cls, statfile, timestep=1, is_leap_year=False):
hour. Default is 1 for one value per hour.
is_leap_year: A boolean to indicate if values are for a leap
year. (Default: False).
use_2017: A boolean to indicate whether the version of the ASHRAE Tau
model that should be the revised version published in 2017 (True)
or the original one published in 2009 (False). (Default: False).
"""
stat = STAT(statfile)

Expand All @@ -352,22 +355,22 @@ def check_missing(opt_data, data_name):
check_missing(stat.monthly_tau_beam, 'monthly_tau_beam')
check_missing(stat.monthly_tau_diffuse, 'monthly_tau_diffuse')

return cls.from_ashrae_revised_clear_sky(stat.location, stat.monthly_tau_beam,
stat.monthly_tau_diffuse, timestep,
is_leap_year)
return cls.from_ashrae_revised_clear_sky(
stat.location, stat.monthly_tau_beam, stat.monthly_tau_diffuse,
timestep, is_leap_year, use_2017)

@classmethod
def from_ashrae_revised_clear_sky(cls, location, monthly_tau_beam,
monthly_tau_diffuse, timestep=1,
is_leap_year=False):
is_leap_year=False, use_2017=False):
"""Create a wea object representing an ASHRAE Revised Clear Sky ("Tau Model")
ASHRAE Revised Clear Skies are intended to determine peak solar load
and sizing parameters for HVAC systems. The revised clear sky is
currently the default recommended sky model used to autosize HVAC
systems in EnergyPlus. For more information on the ASHRAE Revised Clear
Sky model, see the EnergyPlus Engineering Reference:
https://bigladdersoftware.com/epx/docs/8-9/engineering-reference/climate-calculations.html
https://bigladdersoftware.com/epx/docs/23-2/engineering-reference/climate-calculations.html
Args:
location: Ladybug location object.
Expand All @@ -379,6 +382,9 @@ def from_ashrae_revised_clear_sky(cls, location, monthly_tau_beam,
hour. Default is 1 for one value per hour.
is_leap_year: A boolean to indicate if values are for a leap
year. (Default: False).
use_2017: A boolean to indicate whether the version of the ASHRAE Tau
model that should be the revised version published in 2017 (True)
or the original one published in 2009 (False). (Default: False).
"""
# extract metadata
metadata = {'source': location.source, 'country': location.country,
Expand All @@ -397,7 +403,7 @@ def from_ashrae_revised_clear_sky(cls, location, monthly_tau_beam,
direct_norm, diffuse_horiz = [], []
for i_mon, alt_list in enumerate(altitudes):
dir_norm_rad, dif_horiz_rad = ashrae_revised_clear_sky(
alt_list, monthly_tau_beam[i_mon], monthly_tau_diffuse[i_mon])
alt_list, monthly_tau_beam[i_mon], monthly_tau_diffuse[i_mon], use_2017)
direct_norm.extend(dir_norm_rad)
diffuse_horiz.extend(dif_horiz_rad)

Expand Down
Loading

0 comments on commit d66225c

Please sign in to comment.