# coding=utf-8
"""Window frame materials.
The materials here can only be applied as frames to window constructions.
"""
from __future__ import division
from honeybee._lockable import lockable
from honeybee.typing import float_in_range, float_in_range_excl_incl, float_positive
from ._base import _EnergyMaterialBase
from ..properties.extension import EnergyWindowFrameProperties
from ..reader import parse_idf_string
from ..writer import generate_idf_string
[docs]
@lockable
class EnergyWindowFrame(_EnergyMaterialBase):
"""A window frame assigned to a Window Construction.
Args:
identifier: Text string for a unique Material ID. Must be < 100 characters
and not contain any EnergyPlus special characters. This will be used to
identify the object across a model and in the exported IDF.
width: Number for the width of frame in plane of window [m]. The frame
width is assumed to be the same on all sides of window.
conductance: Number for the thermal conductance of the frame material measured
from inside to outside of the frame surface (no air films) and taking 2D
conduction effects into account [W/m2-K]. Values for typical frame
materials are as follows.
* Aluminum with Thermal Break - 56.4 W/m2-K
* Aluminum One-Sided (Flush) - 10.7 W/m2-K
* Wood - 3.5 W/m2-K
* Vinyl - 2.3 W/m2-K
edge_to_center_ratio: Number between 0 and 4 for the ratio of the glass
conductance near the frame (excluding air films) divided by the glass
conductance at the center of the glazing (excluding air films).
This is used only for multi-pane glazing constructions. This ratio should
usually be greater than 1.0 since the spacer material that separates
the glass panes is usually more conductive than the gap between panes.
A value of 1 effectively indicates no spacer. Values should usually be
obtained from the LBNL WINDOW program so that the unique characteristics
of the window construction can be accounted for. (Default: 1).
outside_projection: Number for the distance that the frame projects outward
from the outside face of the glazing [m]. This is used to calculate shadowing
of frame onto glass, solar absorbed by the frame, IR emitted and
absorbed by the frame, and convection from frame. (Default: 0).
inside_projection: Number for the distance that the frame projects inward
from the inside face of the glazing [m]. This is used to calculate solar
absorbed by the frame, IR emitted and absorbed by the frame, and
convection from frame. (Default: 0).
thermal_absorptance: A number between 0 and 1 for the fraction of incident long
wavelength radiation that is absorbed by the material. (Default: 0.9).
solar_absorptance: A number between 0 and 1 for the fraction of incident
solar radiation absorbed by the material. (Default: 0.7).
visible_absorptance: A number between 0 and 1 for the fraction of incident
visible wavelength radiation absorbed by the material.
Default is None, which will yield the same value as solar_absorptance.
Properties:
* identifier
* display_name
* width
* conductance
* edge_to_center_ratio
* outside_projection
* inside_projection
* thermal_absorptance
* solar_absorptance
* visible_absorptance
* solar_reflectance
* visible_reflectance
* u_value
* r_value
* user_data
* properties
"""
__slots__ = ('_identifier', '_display_name', '_width', '_conductance',
'_edge_to_center_ratio', '_outside_projection', '_inside_projection',
'_thermal_absorptance', '_solar_absorptance', '_visible_absorptance')
def __init__(self, identifier, width, conductance, edge_to_center_ratio=1,
outside_projection=0, inside_projection=0, thermal_absorptance=0.9,
solar_absorptance=0.7, visible_absorptance=None):
"""Initialize energy material."""
_EnergyMaterialBase.__init__(self, identifier)
self.width = width
self.conductance = conductance
self.edge_to_center_ratio = edge_to_center_ratio
self.outside_projection = outside_projection
self.inside_projection = inside_projection
self.thermal_absorptance = thermal_absorptance
self.solar_absorptance = solar_absorptance
self.visible_absorptance = visible_absorptance
self._locked = False
self._properties = EnergyWindowFrameProperties(self)
@property
def width(self):
"""Get or set the width of frame in plane of window [m]."""
return self._width
@width.setter
def width(self, value):
self._width = float_in_range_excl_incl(value, 0.0, 1.0, 'window frame width')
@property
def conductance(self):
"""Get or set the conductance of the frame material [W/m2-K]."""
return self._conductance
@conductance.setter
def conductance(self, cond):
self._conductance = float_positive(cond, 'window frame conductance')
@property
def edge_to_center_ratio(self):
"""Get or set the ratio between the edge and center glass conductances."""
return self._edge_to_center_ratio
@edge_to_center_ratio.setter
def edge_to_center_ratio(self, value):
self._edge_to_center_ratio = float_in_range_excl_incl(
value, 0.0, 4.0, 'window frame edge-to-center ratio')
@property
def outside_projection(self):
"""Get or set the distance the frame projects from the outside [m]."""
return self._outside_projection
@outside_projection.setter
def outside_projection(self, value):
self._outside_projection = float_in_range(
value, 0.0, 0.5, 'window frame outside projection')
@property
def inside_projection(self):
"""Get or set the distance the frame projects from the inside [m]."""
return self._inside_projection
@inside_projection.setter
def inside_projection(self, value):
self._inside_projection = float_in_range(
value, 0.0, 0.5, 'window frame inside projection')
@property
def thermal_absorptance(self):
"""Get or set the thermal absorptance of the frame material."""
return self._thermal_absorptance
@thermal_absorptance.setter
def thermal_absorptance(self, t_abs):
self._thermal_absorptance = float_in_range(
t_abs, 0.0, 1.0, 'window frame thermal absorptance')
@property
def solar_absorptance(self):
"""Get or set the solar absorptance of the frame material."""
return self._solar_absorptance
@solar_absorptance.setter
def solar_absorptance(self, s_abs):
self._solar_absorptance = float_in_range(
s_abs, 0.0, 1.0, 'window frame solar absorptance')
@property
def visible_absorptance(self):
"""Get or set the visible absorptance of the frame material."""
return self._visible_absorptance if self._visible_absorptance is not None \
else self._solar_absorptance
@visible_absorptance.setter
def visible_absorptance(self, v_abs):
self._visible_absorptance = float_in_range(
v_abs, 0.0, 1.0, 'window frame visible absorptance') if v_abs is not None \
else None
@property
def solar_reflectance(self):
"""Get or set the front solar reflectance of the frame material."""
return 1 - self.solar_absorptance
@solar_reflectance.setter
def solar_reflectance(self, v_ref):
v_ref = float_in_range(v_ref, 0.0, 1.0, 'window frame solar reflectance')
self.solar_absorptance = 1 - v_ref
@property
def visible_reflectance(self):
"""Get or set the front visible reflectance of the frame material."""
return 1 - self.visible_absorptance
@visible_reflectance.setter
def visible_reflectance(self, v_ref):
v_ref = float_in_range(v_ref, 0.0, 1.0, 'window frame visible reflectance')
self.visible_absorptance = 1 - v_ref
@property
def r_value(self):
"""Get or set the R-value of the frame material in [m2-K/W] (excluding films).
"""
return 1 / self.conductance
@r_value.setter
def r_value(self, r_val):
_new_conductance = 1 / float_positive(r_val, 'window frame r-value')
self._conductance = _new_conductance
@property
def u_value(self):
"""Get or set the U-value of the frame material [W/m2-K] (excluding films).
"""
return self.conductance
@u_value.setter
def u_value(self, u_val):
self.conductance = u_val
[docs]
@classmethod
def from_idf(cls, idf_string):
"""Create an EnergyWindowFrame from an EnergyPlus text string.
Args:
idf_string: A text string fully describing an EnergyPlus material.
"""
ep_strs = parse_idf_string(idf_string, 'WindowProperty:FrameAndDivider,')
idf_defaults = ('unnamed', 0, 0, 0, 0, 1, 0.7, 0.7, 0.9)
for i, d_val in enumerate(idf_defaults): # fill in any default values
try:
if ep_strs[i] == '':
ep_strs[i] = d_val
except IndexError:
ep_strs.append(d_val)
if float(ep_strs[1]) == 0 or float(ep_strs[4]) == 0:
return None # no frame definition within WindowProperty:FrameAndDivider
return cls(
ep_strs[0], ep_strs[1], ep_strs[4], ep_strs[5], ep_strs[2], ep_strs[3],
ep_strs[6], ep_strs[7], ep_strs[8])
[docs]
@classmethod
def from_dict(cls, data):
"""Create a EnergyWindowFrame from a dictionary.
Args:
data: A python dictionary in the following format
.. code-block:: python
{
"type": 'EnergyWindowFrame',
"identifier": 'Wood_Frame_050_032',
"display_name": 'Pine Wooden Frame',
"width": 0.05,
"conductance": 3.2,
"edge_to_center_ratio": 2.6,
"outside_projection": 0.05,
"inside_projection": 0.1,
"thermal_absorptance": 0.9,
"solar_absorptance": 0.7,
"visible_absorptance": 0.7
}
"""
assert data['type'] == 'EnergyWindowFrame', \
'Expected EnergyWindowFrame. Got {}.'.format(data['type'])
ratio = data['edge_to_center_ratio'] if 'edge_to_center_ratio' in data and \
data['edge_to_center_ratio'] is not None else 1
out_pro = data['outside_projection'] if 'outside_projection' in data and \
data['outside_projection'] is not None else 0
in_pro = data['inside_projection'] if 'inside_projection' in data and \
data['inside_projection'] is not None else 0
t_abs = data['thermal_absorptance'] if 'thermal_absorptance' in data and \
data['thermal_absorptance'] is not None else 0.9
s_abs = data['solar_absorptance'] if 'solar_absorptance' in data and \
data['solar_absorptance'] is not None else 0.7
v_abs = data['visible_absorptance'] if 'visible_absorptance' in data else None
new_mat = cls(data['identifier'], data['width'], data['conductance'],
ratio, out_pro, in_pro, t_abs, s_abs, v_abs)
if 'display_name' in data and data['display_name'] is not None:
new_mat.display_name = data['display_name']
if 'user_data' in data and data['user_data'] is not None:
new_mat.user_data = data['user_data']
if 'properties' in data and data['properties'] is not None:
new_mat._properties._load_extension_attr_from_dict(data['properties'])
return new_mat
[docs]
def to_idf(self):
"""Get an EnergyPlus string representation of the window frame.
.. code-block:: shell
WindowProperty:FrameAndDivider,
TestFrameAndDivider, ! Frame/Divider Name
0.05, ! Frame Width
0.04, ! Frame Outside Projection
0.03, ! Frame Inside Projection
5.0, ! Frame Conductance
1.3, ! Ratio of Frame-Edge Glass Conductance to Center-Of-Glass Conductance
0.8, ! Frame Solar Absorptance
0.8, ! Frame Visible Absorptance
"""
values = (
self.identifier, self.width, self.outside_projection, self.inside_projection,
self.conductance, self.edge_to_center_ratio, self.solar_absorptance,
self.visible_absorptance, self.thermal_absorptance)
comments = (
'name', 'width {m}', 'outside projection {m}', 'inside projection {m}',
'conductance {W/m2-K}', 'edge-to-center-of-glass conductance ratio',
'solar absorptance', 'visible absorptance', 'thermal absorptance')
return generate_idf_string('WindowProperty:FrameAndDivider', values, comments)
[docs]
def to_dict(self):
"""EnergyWindowFrame dictionary representation."""
base = {
'type': 'EnergyWindowFrame',
'identifier': self.identifier,
'width': self.width,
'conductance': self.conductance,
'edge_to_center_ratio': self.edge_to_center_ratio,
'outside_projection': self.outside_projection,
'inside_projection': self.inside_projection,
'thermal_absorptance': self.thermal_absorptance,
'solar_absorptance': self.solar_absorptance,
'visible_absorptance': self.visible_absorptance
}
if self._display_name is not None:
base['display_name'] = self.display_name
if self._user_data is not None:
base['user_data'] = self.user_data
prop_dict = self._properties.to_dict()
if prop_dict is not None:
base['properties'] = prop_dict
return base
def __key(self):
"""A tuple based on the object properties, useful for hashing."""
return (
self.identifier, self.width, self.conductance, self.edge_to_center_ratio,
self.outside_projection, self.inside_projection,
self.thermal_absorptance, self.solar_absorptance, self.visible_absorptance)
def __hash__(self):
return hash(self.__key())
def __eq__(self, other):
return isinstance(other, EnergyWindowFrame) and self.__key() == other.__key()
def __ne__(self, other):
return not self.__eq__(other)
def __repr__(self):
return self.to_idf()
def __copy__(self):
new_material = self.__class__(
self.identifier, self.width, self.conductance, self.edge_to_center_ratio,
self.outside_projection, self.inside_projection, self.thermal_absorptance,
self.solar_absorptance, self._visible_absorptance)
new_material._display_name = self._display_name
new_material._user_data = None if self._user_data is None \
else self._user_data.copy()
new_material._properties._duplicate_extension_attr(self._properties)
return new_material