Source code for honeybee_energy.properties.face

# coding=utf-8
"""Face Energy Properties."""
from honeybee.facetype import AirBoundary
from honeybee.checkdup import is_equivalent
from honeybee.units import conversion_factor_to_meters

from ..construction.opaque import OpaqueConstruction
from ..construction.air import AirBoundaryConstruction
from ..lib.constructionsets import generic_construction_set
from ..ventcool.crack import AFNCrack


[docs]class FaceEnergyProperties(object): """Energy Properties for Honeybee Face. Args: host: A honeybee_core Face object that hosts these properties. construction: An optional Honeybee OpaqueConstruction object for the face. If None, it will be set by the parent Room ConstructionSet or the the Honeybee default generic ConstructionSet. vent_crack: An optional AFNCrack to specify the air leakage crack for the Face. (Default: None). Properties: * host * construction * vent_crack * is_construction_set_on_object """ __slots__ = ('_host', '_construction', '_vent_crack') def __init__(self, host, construction=None, vent_crack=None): """Initialize Face energy properties.""" self._host = host self.construction = construction self.vent_crack = vent_crack @property def host(self): """Get the Face object hosting these properties.""" return self._host @property def construction(self): """Get or set Face Construction. If the Construction is not set on the face-level, then it will be assigned based on the ConstructionSet assigned to the parent Room. If there is no parent Room or the parent Room's ConstructionSet has no construction for the Face type and boundary_condition, it will be assigned using the honeybee default generic construction set. """ if self._construction: # set by user return self._construction elif self._host.has_parent: # set by parent room constr_set = self._host.parent.properties.energy.construction_set return constr_set.get_face_construction( self._host.type.name, self._host.boundary_condition.name) else: return generic_construction_set.get_face_construction( self._host.type.name, self._host.boundary_condition.name) @construction.setter def construction(self, value): if value is not None: if isinstance(self.host.type, AirBoundary): accept_cons = (AirBoundaryConstruction, OpaqueConstruction) assert isinstance(value, accept_cons), \ 'Expected Air Boundary or Opaque Construction for face with ' \ 'AirBoundary type. Got {}'.format(type(value)) else: assert isinstance(value, OpaqueConstruction), \ 'Expected Opaque Construction for face. Got {}'.format(type(value)) value.lock() # lock editing in case construction has multiple references self._construction = value @property def vent_crack(self): """Get or set a AFNCrack object to specify Airflow Network air leakage. Note that anything assigned here has no bearing on the simulation unless the Model that the Face is a part of has its ventilation_simulation_control set for MultiZone air flow, thereby triggering the use of the AirflowNetwork. """ return self._vent_crack @vent_crack.setter def vent_crack(self, value): if value is not None: assert isinstance(value, AFNCrack), 'Expected AFNCrack ' \ 'for Face vent_crack. Got {}'.format(type(value)) value.lock() # lock because we don't duplicate the object self._vent_crack = value @property def is_construction_set_on_object(self): """Boolean noting if construction is assigned on the level of this Face. This is opposed to having the construction assigned by a ConstructionSet. """ return self._construction is not None
[docs] def r_factor(self, units='Meters'): """Get the Face R-factor [m2-K/W] (including air film resistance). The air film resistances are computed using the orientation and height of the Face geometry. Args: units: Text for the units in which the Face geometry exists. These will be used to correctly interpret the dimensions of the geometry for heat flow calculation. (Default: Meters). """ constr = self.construction if isinstance(constr, AirBoundaryConstruction): return 0 u_conv = conversion_factor_to_meters(units) height = (self.host.max.z - self.host.min.z) * u_conv height = 1 if height < 1 else height temps, r_vals = constr.temperature_profile( height=height, angle=abs(self.host.altitude - 90)) return sum(r_vals)
[docs] def u_factor(self, units='Meters'): """Get the Face U-factor [W/m2-K] (including resistances for air films). The air film resistances are computed using the orientation and height of the Face geometry. Args: units: Text for the units in which the Face geometry exists. These will be used to correctly interpret the dimensions of the geometry for heat flow calculation. (Default: Meters). """ try: return 1 / self.r_factor(units) except ZeroDivisionError: return 0 # AirBoundary construction
[docs] def shgc(self, units='Meters'): """Get the Face solar heat gain coefficient (SHGC). This value is computed by summing the conducted portions of solar irradiance under the NFRC summer conditions. The air film resistances are computed using the orientation and height of the Face geometry. Args: units: Text for the units in which the Face geometry exists. These will be used to correctly interpret the dimensions of the geometry for heat flow calculation. (Default: Meters). """ constr = self.construction if isinstance(constr, AirBoundaryConstruction): return 1 # compute the temperature profile t_out, t_in, sol_irr = 32, 24, 783 # NFRC 2010 summer conditions u_conv = conversion_factor_to_meters(units) height = (self.host.max.z - self.host.min.z) * u_conv height = 1 if height < 1 else height _, r_vals = constr.temperature_profile( t_out, t_in, height=height, angle=abs(self.host.altitude - 90), solar_irradiance=sol_irr) heat_gen = sol_irr * (1 - constr.outside_solar_reflectance) r_factor = sum(r_vals) conducted = heat_gen * (1 - (sum(r_vals[1:]) / r_factor)) return conducted / sol_irr
[docs] def reset_construction_to_set(self): """Reset the construction assigned to this Face and its children to the default. This means that the Face's construction and its child Aperture/Door constructions will be assigned by a ConstructionSet. """ self._construction = None for sf in self.host.sub_faces: sf.properties.energy.reset_construction_to_set() for shade in self.host.shades: shade.properties.energy.reset_construction_to_set()
[docs] @classmethod def from_dict(cls, data, host): """Create FaceEnergyProperties from a dictionary. Note that the dictionary must be a non-abridged version for this classmethod to work. Args: data: A dictionary representation of FaceEnergyProperties with the format below. host: A Face object that hosts these properties. .. code-block:: python { "type": 'FaceEnergyProperties', "construction": {}, # opaque construction "vent_crack": {} # AFN crack } """ assert data['type'] == 'FaceEnergyProperties', \ 'Expected FaceEnergyProperties. Got {}.'.format(data['type']) new_prop = cls(host) if 'construction' in data and data['construction'] is not None: new_prop.construction = OpaqueConstruction.from_dict(data['construction']) if 'vent_crack' in data and data['vent_crack'] is not None: new_prop.vent_crack = AFNCrack.from_dict(data['vent_crack']) return new_prop
[docs] def apply_properties_from_dict(self, abridged_data, constructions): """Apply properties from a FaceEnergyPropertiesAbridged dictionary. Args: abridged_data: A FaceEnergyPropertiesAbridged dictionary (typically coming from a Model). constructions: A dictionary of constructions with constructions identifiers as keys, which will be used to re-assign constructions. """ if 'construction' in abridged_data and abridged_data['construction'] is not None: try: self.construction = constructions[abridged_data['construction']] except KeyError: raise ValueError('Face construction "{}" was not found in ' 'constructions.'.format(abridged_data['construction'])) if 'vent_crack' in abridged_data and abridged_data['vent_crack'] is not None: self.vent_crack = AFNCrack.from_dict(abridged_data['vent_crack'])
[docs] def to_dict(self, abridged=False): """Return energy properties as a dictionary. Args: abridged: Boolean to note whether the full dictionary describing the object should be returned (False) or just an abridged version (True). Default: False. """ base = {'energy': {}} base['energy']['type'] = 'FaceEnergyProperties' if not \ abridged else 'FaceEnergyPropertiesAbridged' if self._construction is not None: base['energy']['construction'] = \ self._construction.identifier if abridged else \ self._construction.to_dict() if self._vent_crack is not None: base['energy']['vent_crack'] = self._vent_crack.to_dict() return base
[docs] def duplicate(self, new_host=None): """Get a copy of this object. Args: new_host: A new Face object that hosts these properties. If None, the properties will be duplicated with the same host. """ _host = new_host or self._host return FaceEnergyProperties(_host, self._construction, self._vent_crack)
[docs] def is_equivalent(self, other): """Check to see if these energy properties are equivalent to another object. This will only be True if all properties match (except for the host) and will otherwise be False. """ if not is_equivalent(self._construction, other._construction): return False if not is_equivalent(self._vent_crack, other._vent_crack): return False return True
[docs] def ToString(self): return self.__repr__()
def __repr__(self): return 'Face Energy Properties: [host: {}]'.format(self.host.display_name)