Source code for ladybug_comfort.parameter.adaptive

# coding=utf-8
"""Parameters for specifying acceptable thermal conditions using the Adaptive model."""
from __future__ import division
import re

from ._base import ComfortParameter
from ..adaptive import neutral_temperature_conditioned, \
    ashrae55_neutral_offset_from_ppd, en15251_neutral_offset_from_comfort_class


[docs] class AdaptiveParameter(ComfortParameter): """Parameters of Adaptive comfort. Args: ashrae_or_en: A boolean to note whether to use the ASHRAE-55 neutral temperature function (True) or the european neutral function (False), which is consistent with both EN-15251 and EN-16798. Note that this input will also determine default values for many of the other properties of this object. neutral_offset: The number of degrees Celsius from the neutral temperature where the input operative temperature is considered acceptable. The default is 2.5C when the neutral temperature function is ASHRAE-55 and 3C when the neutral temperature function is EN, which is consistent with comfort class II. You may want to use the set_neutral_offset_from_ppd() or the set_neutral_offset_from_comfort_class() methods on this object to set this value using ppd from the ASHRAE-55 standard or comfort classes from the EN standard respectively. avg_month_or_running_mean: A boolean to note whether the prevailing outdoor temperature is computed from the average monthly temperature (True) or a weighted running mean of the last week (False). The default is True when the neutral temperature function is ASHRAE-55 and False when the neutral temperature function is EN. discrete_or_continuous_air_speed: A boolean to note whether discrete categories should be used to assess the effect of elevated air speed (True) or whether a continuous function should be used (False). Note that continuous air speeds were only used in the older EN-15251 standard and are not a part of the more recent EN-16798 standard. When unassigned, this will be True for discrete air speeds. cold_prevail_temp_limit: A number indicating the prevailing outdoor temperature below which acceptable indoor operative temperatures flat line. The default is 10C, which is consistent with both ASHRAE-55 and EN-16798. However, 15C was used for the older EN-15251 standard. This number cannot be greater than 22C and cannot be less than 10C. conditioning: A number between 0 and 1 that represents how "conditioned" vs. "free-running" the building is. * 0 = free-running (completely passive with no air conditioning) * 1 = conditioned (no operable windows and fully air conditioned) The default is 0 since both the ASHRAE-55 and EN standards prohibit the use of adaptive comfort methods when a cooling system is active. Properties: * ashrae_or_en * neutral_offset * avg_month_or_running_mean * discrete_or_continuous_air_speed * cold_prevail_temp_limit * conditioning * standard * prevailing_temperature_method * minimum_operative """ _model = 'Adaptive' __slots__ = ('_standard', '_neutral_offset', '_prevail_method', '_air_speed_method', '_cold_prevail_temp_limit', '_conditioning', '_min_operative') def __init__(self, ashrae_or_en=None, neutral_offset=None, avg_month_or_running_mean=None, discrete_or_continuous_air_speed=None, cold_prevail_temp_limit=None, conditioning=None): """Initialize Adaptive Parameters. """ # get the standard self._standard = ashrae_or_en if ashrae_or_en is not None else True assert isinstance(self._standard, bool), 'ashrae_or_en must be '\ 'a boolean. Got {}'.format(type(self._standard)) # set defaults based on the standard default_air_speed_method = True default_cold_prevail_temp_limit = 10 if self._standard: default_neutral_offset = 2.5 default_prevail_method = True else: default_neutral_offset = 3 default_prevail_method = False # assign properties based on defaults and input self._prevail_method = avg_month_or_running_mean if \ avg_month_or_running_mean is not None else default_prevail_method self._air_speed_method = discrete_or_continuous_air_speed if \ discrete_or_continuous_air_speed is not None else default_air_speed_method self._cold_prevail_temp_limit = cold_prevail_temp_limit if \ cold_prevail_temp_limit is not None else default_cold_prevail_temp_limit self._conditioning = conditioning if conditioning is not None else 0 # perform range checks on the inputs assert 10 <= self._cold_prevail_temp_limit <= 22, \ 'cold_prevail_temp_limit must be between 10 and 22. Got {}'.format( self._cold_prevail_temp_limit) assert 0 <= self._conditioning <= 1, \ 'conditioning must be between 0 and 1. Got {}'.format(self._conditioning) # assign the neutral temperature offset self.neutral_offset = neutral_offset if \ neutral_offset is not None else default_neutral_offset
[docs] @classmethod def from_dict(cls, data): """Create a AdaptiveParameter object from a dictionary. Args: data: A AdaptiveParameter dictionary in following the format below. .. code-block:: python { 'type': 'AdaptiveParameter', 'ashrae_or_en': True, 'neutral_offset': 2.5, 'avg_month_or_running_mean': False, 'discrete_or_continuous_air_speed': True, 'cold_prevail_temp_limit': 10, 'conditioning': 0 } """ assert data['type'] == 'AdaptiveParameter', \ 'Expected AdaptiveParameter dictionary. Got {}.'.format(data['type']) ashrae_or_en = data['ashrae_or_en'] if \ 'ashrae_or_en' in data else None neutral_offset = data['neutral_offset'] if \ 'neutral_offset' in data else None avg_month_or_running_mean = data['avg_month_or_running_mean'] if \ 'avg_month_or_running_mean' in data else None discrete_or_continuous_air_speed = data['discrete_or_continuous_air_speed'] if \ 'discrete_or_continuous_air_speed' in data else None cold_prevail_temp_limit = data['cold_prevail_temp_limit'] if \ 'cold_prevail_temp_limit' in data else None conditioning = data['conditioning'] if \ 'conditioning' in data else None return cls(ashrae_or_en, neutral_offset, avg_month_or_running_mean, discrete_or_continuous_air_speed, cold_prevail_temp_limit, conditioning)
[docs] @classmethod def from_string(cls, adaptive_parameter_string): """Create an AdaptiveParameter object from an AdaptiveParameter string.""" str_pattern = re.compile(r"\-\-(\S*\s\S*)") matches = str_pattern.findall(adaptive_parameter_string) par_dict = {item.split(' ')[0]: item.split(' ')[1] for item in matches} ashrae55 = True if 'standard' not in par_dict \ or par_dict['standard'].upper() == 'ASHRAE-55' else False offset = float(par_dict['neutral-offset']) \ if 'neutral-offset' in par_dict else None avg_month = None if 'prevail-method' in par_dict: avg_month = True if par_dict['prevail-method'].lower() == 'averagedmonthly' \ else False spd_method = None if 'air-speed-method' in par_dict: spd_method = True if par_dict['air-speed-method'].lower() == 'discrete' \ else False cold_limit = float(par_dict['cold-limit']) \ if 'cold-limit' in par_dict else None conditioning = float(par_dict['conditioning']) \ if 'conditioning' in par_dict else None return cls(ashrae55, offset, avg_month, spd_method, cold_limit, conditioning)
@property def ashrae_or_en(self): """A boolean to note whether to use the ASHRAE-55 neutral temperature function (True) or the EN function (False).""" return self._standard @property def neutral_offset(self): """The degrees Celsius from the neutral temperature where the operative temperature is considered acceptable.""" return self._neutral_offset @neutral_offset.setter def neutral_offset(self, offset): assert 0 < offset <= 10, \ 'neutral_offset must be between 0 and 10 C. Got {}'.format(offset) self._neutral_offset = offset self._calc_min_operative_temperature() @property def avg_month_or_running_mean(self): """Boolean noting whether prevailing outdoor temperature is computed from the average monthly temperature (True) or a weighted running mean (False).""" return self._prevail_method @property def discrete_or_continuous_air_speed(self): """Boolean noting whether discrete categories are used to assess elevated air speed (True) or whether a continuous function is used (False).""" return self._air_speed_method @property def cold_prevail_temp_limit(self): """The prevailing outdoor temperature below which acceptable indoor operative temperatures flat line. [C]""" return self._cold_prevail_temp_limit @property def conditioning(self): """A decimal noting how conditioned(1) vs. free-running(0) the building is.""" return self._conditioning @property def standard(self): """Text denoting the standard. Either 'ASHRAE-55' or 'EN-16798' """ if self._standard is True: return 'ASHRAE-55' else: return 'EN-16798' @property def prevailing_temperature_method(self): """Text denoting prevailing temperature method. Either 'Averaged Monthly' or 'Running Mean'. """ if self._prevail_method is True: return 'AveragedMonthly' else: return 'RunningMean' @property def air_speed_method(self): """Text denoting the type of function used for the cooling effect of air speed. Either 'Discrete' or 'Continuous'. """ if self._air_speed_method is True: return 'Discrete' else: return 'Continuous' @property def minimum_operative(self): """Operative Temperature in C below which conditions cannot be comfortable.""" return self._min_operative
[docs] def set_neutral_offset_from_ppd(self, ppd): """Set the offset from neutral temperature given the ASHRAE-55 PPD limit.""" self.neutral_offset = ashrae55_neutral_offset_from_ppd(ppd)
[docs] def set_neutral_offset_from_comfort_class(self, comfort_class): """Set the offset from neutral temperature given the EN comfort class.""" self.neutral_offset = en15251_neutral_offset_from_comfort_class(comfort_class)
[docs] def is_comfortable(self, comfort_result, cooling_effect=0): """Determine if conditions are comfortable or not. Values are one of the following: * 0 = uncomfortable * 1 = comfortable Args: comfort_result: An adaptive comfort result dictionary from the adaptive_comfort_ashrae55 or adaptive_comfort_en15251 functions. cooling_effect: Cooling effect from elevated air speed. """ if self._standard: return 1 if (comfort_result['to'] >= self._min_operative and comfort_result['deg_comf'] >= -self.neutral_offset and comfort_result['deg_comf'] <= self.neutral_offset + cooling_effect) else 0 else: # lower threshold of EN-16798 is 1 degree cooler than upper threshold return 1 if (comfort_result['to'] >= self._min_operative and comfort_result['deg_comf'] >= -self.neutral_offset - 1 and comfort_result['deg_comf'] <= self.neutral_offset + cooling_effect) else 0
[docs] def thermal_condition(self, comfort_result, cooling_effect=0): """Determine whether conditions are cold, neutral or hot. Values are one of the following: * -1 = cold * 0 = neutral * +1 = hot Args: comfort_result: An adaptive comfort result dictionary from the adaptive_comfort_ashrae55 or adaptive_comfort_en15251 functions. cooling_effect: Cooling effect from elevated air speed """ if self.is_comfortable(comfort_result, cooling_effect) == 0: return 1 if comfort_result['deg_comf'] > 0 else -1 else: return 0
[docs] def to_dict(self): """AdaptiveParameter dictionary representation.""" return { 'type': 'AdaptiveParameter', 'ashrae_or_en': self.ashrae_or_en, 'neutral_offset': self.neutral_offset, 'avg_month_or_running_mean': self.avg_month_or_running_mean, 'discrete_or_continuous_air_speed': self.discrete_or_continuous_air_speed, 'cold_prevail_temp_limit': self.cold_prevail_temp_limit, 'conditioning': self.conditioning }
def __copy__(self): return AdaptiveParameter(self.ashrae_or_en, self.neutral_offset, self.avg_month_or_running_mean, self.discrete_or_continuous_air_speed, self.cold_prevail_temp_limit, self.conditioning) def _calc_min_operative_temperature(self): """Set operative temperature below which conditions cannot be comfortable.""" self._min_operative = neutral_temperature_conditioned( self._cold_prevail_temp_limit, self._conditioning, self.standard) \ - self._neutral_offset def __repr__(self): """Adaptive comfort parameters representation.""" return '--standard {} --neutral-offset {} ' \ '--prevail-method {} --air-speed-method {} ' \ '--cold-limit {} --conditioning {}'.format( self.standard, self.neutral_offset, self.prevailing_temperature_method, self.air_speed_method, self.cold_prevail_temp_limit, self.conditioning)