Source code for honeybee_energy.material.opaque

# coding=utf-8
"""Opaque energy materials.

The materials here are the only ones that can be used in opaque constructions.
"""
from __future__ import division

from ._base import _EnergyMaterialOpaqueBase
from ..reader import parse_idf_string
from ..writer import generate_idf_string

from honeybee._lockable import lockable
from honeybee.typing import float_in_range, float_positive, clean_rad_string
from ..properties.extension import EnergyMaterialProperties, \
    EnergyMaterialNoMassProperties, EnergyMaterialVegetationProperties


[docs] @lockable class EnergyMaterial(_EnergyMaterialOpaqueBase): """Typical opaque energy material. 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. thickness: Number for the thickness of the material layer [m]. conductivity: Number for the thermal conductivity of the material [W/m-K]. density: Number for the density of the material [kg/m3]. specific_heat: Number for the specific heat of the material [J/kg-K]. roughness: Text describing the relative roughness of the material. (Default: MediumRough). Must be one of the following: * VeryRough * Rough * MediumRough * MediumSmooth * Smooth * VerySmooth 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 * roughness * thickness * conductivity * density * specific_heat * thermal_absorptance * solar_absorptance * visible_absorptance * solar_reflectance * visible_reflectance * resistivity * u_value * r_value * mass_area_density * area_heat_capacity * user_data * properties """ __slots__ = ('_roughness', '_thickness', '_conductivity', '_density', '_specific_heat', '_thermal_absorptance', '_solar_absorptance', '_visible_absorptance') def __init__(self, identifier, thickness, conductivity, density, specific_heat, roughness='MediumRough', thermal_absorptance=0.9, solar_absorptance=0.7, visible_absorptance=None): """Initialize energy material.""" _EnergyMaterialOpaqueBase.__init__(self, identifier) self.thickness = thickness self.conductivity = conductivity self.density = density self.specific_heat = specific_heat self.roughness = roughness self.thermal_absorptance = thermal_absorptance self.solar_absorptance = solar_absorptance self.visible_absorptance = visible_absorptance self._locked = False self._properties = EnergyMaterialProperties(self) @property def roughness(self): """Get or set the text describing the roughness of the material layer.""" return self._roughness @roughness.setter def roughness(self, rough): assert rough in self.ROUGHTYPES, 'Invalid input "{}" for material roughness.' \ ' Roughness must be one of the following:\n{}'.format( rough, self.ROUGHTYPES) self._roughness = rough @property def thickness(self): """Get or set the thickness of the material layer [m].""" return self._thickness @thickness.setter def thickness(self, thick): self._thickness = float_positive(thick, 'material thickness') assert self._thickness != 0, 'Material thickness must be greater than zero.' @property def conductivity(self): """Get or set the conductivity of the material layer [W/m-K].""" return self._conductivity @conductivity.setter def conductivity(self, cond): self._conductivity = float_positive(cond, 'material conductivity') @property def density(self): """Get or set the density of the material layer [kg/m3].""" return self._density @density.setter def density(self, dens): self._density = float_positive(dens, 'material density') @property def specific_heat(self): """Get or set the specific heat of the material layer [J/kg-K].""" return self._specific_heat @specific_heat.setter def specific_heat(self, sp_ht): self._specific_heat = float_in_range( sp_ht, 100.0, input_name='material specific heat') @property def thermal_absorptance(self): """Get or set the thermal absorptance of the material layer.""" 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, 'material thermal absorptance') @property def solar_absorptance(self): """Get or set the solar absorptance of the material layer.""" 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, 'material solar absorptance') @property def visible_absorptance(self): """Get or set the visible absorptance of the material layer.""" 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, 'material visible absorptance') if v_abs is not None \ else None @property def solar_reflectance(self): """Get or set the front solar reflectance of the material layer.""" 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, 'material solar reflectance') self.solar_absorptance = 1 - v_ref @property def visible_reflectance(self): """Get or set the front visible reflectance of the material layer.""" 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, 'material visible reflectance') self.visible_absorptance = 1 - v_ref @property def resistivity(self): """Get or set the resistivity of the material layer [m-K/W].""" return 1 / self._conductivity @resistivity.setter def resistivity(self, resis): self._conductivity = 1 / float_positive(resis, 'material resistivity') @property def r_value(self): """Get or set the R-value of the material in [m2-K/W] (excluding air films). Note that, when setting the R-value, the thickness of the material will remain fixed and only the conductivity will be adjusted. """ return self.thickness / self.conductivity @r_value.setter def r_value(self, r_val): _new_conductivity = self.thickness / \ float_positive(r_val, 'material r-value') self._conductivity = _new_conductivity @property def u_value(self): """Get or set the U-value of the material [W/m2-K] (excluding air films). Note that, when setting the R-value, the thickness of the material will remain fixed and only the conductivity will be adjusted. """ return self.conductivity / self.thickness @u_value.setter def u_value(self, u_val): self.r_value = 1 / float_positive(u_val, 'material u-value') @property def mass_area_density(self): """The area density of the material [kg/m2].""" return self.thickness * self.density @property def area_heat_capacity(self): """The heat capacity per unit area of the material [J/K-m2].""" return self.mass_area_density * self.specific_heat
[docs] @classmethod def from_idf(cls, idf_string): """Create an EnergyMaterial from an EnergyPlus text string. Args: idf_string: A text string fully describing an EnergyPlus material. """ ep_strs = parse_idf_string(idf_string, 'Material,') idf_defaults = {6: 0.9, 7: 0.7, 8: 0.7} for i, ep_str in enumerate(ep_strs): # fill in any default values if ep_str == '' and i in idf_defaults: ep_strs[i] = idf_defaults[i] ep_strs.insert(5, ep_strs.pop(1)) # move roughness to correct place return cls(*ep_strs)
[docs] @classmethod def from_dict(cls, data): """Create a EnergyMaterial from a dictionary. Args: data: A python dictionary in the following format .. code-block:: python { "type": 'EnergyMaterial', "identifier": 'Concrete_020_231_2322_832', "display_name": 'Concrete Slab', "roughness": 'MediumRough', "thickness": 0.2, "conductivity": 2.31, "density": 2322, "specific_heat": 832, "thermal_absorptance": 0.9, "solar_absorptance": 0.7, "visible_absorptance": 0.7 } """ assert data['type'] == 'EnergyMaterial', \ 'Expected EnergyMaterial. Got {}.'.format(data['type']) rough = data['roughness'] if 'roughness' in data and \ data['roughness'] is not None else 'MediumRough' 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['thickness'], data['conductivity'], data['density'], data['specific_heat'], rough, 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 material. .. code-block:: shell Material,A2 - 4 IN DENSE FACE BRICK, ! Material Name Rough, ! Roughness 0.1014984, ! Thickness {m} 1.245296, ! Conductivity {W/M*K} 2082.400, ! Density {Kg/M**3} 920.4800, ! Specific Heat {J/Kg*K} 0.9000000, ! Thermal Absorptance 0.9300000, ! Solar Absorptance 0.9300000; ! Visible Absorptance """ values = (self.identifier, self.roughness, self.thickness, self.conductivity, self.density, self.specific_heat, self.thermal_absorptance, self.solar_absorptance, self.visible_absorptance) comments = ('name', 'roughness', 'thickness {m}', 'conductivity {W/m-K}', 'density {kg/m3}', 'specific heat {J/kg-K}', 'thermal absorptance', 'solar absorptance', 'visible absorptance') return generate_idf_string('Material', values, comments)
[docs] def to_radiance_solar(self, specularity=0.0): """Honeybee Radiance material from the solar reflectance of this material.""" try: from honeybee_radiance.modifier.material import Plastic except ImportError as e: raise ImportError('honeybee_radiance library must be installed to use ' 'to_radiance_solar() method. {}'.format(e)) return Plastic.from_single_reflectance( clean_rad_string(self.identifier), 1 - self.solar_absorptance, specularity, self.RADIANCEROUGHTYPES[self.roughness])
[docs] def to_radiance_visible(self, specularity=0.0): """Honeybee Radiance material from the visible reflectance of this material.""" try: from honeybee_radiance.modifier.material import Plastic except ImportError as e: raise ImportError('honeybee_radiance library must be installed to use ' 'to_radiance_solar() method. {}'.format(e)) return Plastic.from_single_reflectance( clean_rad_string(self.identifier), 1 - self.visible_absorptance, specularity, self.RADIANCEROUGHTYPES[self.roughness])
[docs] def to_dict(self): """Energy Material dictionary representation.""" base = { 'type': 'EnergyMaterial', 'identifier': self.identifier, 'roughness': self.roughness, 'thickness': self.thickness, 'conductivity': self.conductivity, 'density': self.density, 'specific_heat': self.specific_heat, '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.roughness, self.thickness, self.conductivity, self.density, self.specific_heat, self.thermal_absorptance, self.solar_absorptance, self.visible_absorptance) def __hash__(self): return hash(self.__key()) def __eq__(self, other): return isinstance(other, EnergyMaterial) 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.thickness, self.conductivity, self.density, self.specific_heat, self.roughness, 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
[docs] @lockable class EnergyMaterialNoMass(_EnergyMaterialOpaqueBase): """Typical no mass opaque energy material. 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. r_value: Number for the R-value of the material [m2-K/W]. roughness: Text describing the relative roughness of the material. Must be one of the following: 'VeryRough', 'Rough', 'MediumRough', 'MediumSmooth', 'Smooth', 'VerySmooth'. Default: 'MediumRough'. 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 value is None, which will use the same value as the solar_absorptance. Properties: * identifier * display_name * r_value * u_value * roughness * thermal_absorptance * solar_absorptance * visible_absorptance * solar_reflectance * visible_reflectance * mass_area_density * area_heat_capacity * user_data * properties """ __slots__ = ('_r_value', '_roughness', '_thermal_absorptance', '_solar_absorptance', '_visible_absorptance') def __init__(self, identifier, r_value, roughness='MediumRough', thermal_absorptance=0.9, solar_absorptance=0.7, visible_absorptance=None): """Initialize energy material.""" _EnergyMaterialOpaqueBase.__init__(self, identifier) self.r_value = r_value self.roughness = roughness self.thermal_absorptance = thermal_absorptance self.solar_absorptance = solar_absorptance self.visible_absorptance = visible_absorptance self._properties = EnergyMaterialNoMassProperties(self) @property def r_value(self): """Get or set the r_value of the material layer [m2-K/W] (excluding air films). """ return self._r_value @r_value.setter def r_value(self, r_val): self._r_value = float_positive(r_val, 'material r-value') @property def u_value(self): """U-value of the material layer [W/m2-K] (excluding air films).""" return 1 / self.r_value @u_value.setter def u_value(self, u_val): self._r_value = 1 / float_positive(u_val, 'material u-value') @property def roughness(self): """Get or set the text describing the roughness of the material layer.""" return self._roughness @roughness.setter def roughness(self, rough): assert rough in self.ROUGHTYPES, 'Invalid input "{}" for material roughness.' \ ' Roughness must be one of the following:\n{}'.format( rough, self.ROUGHTYPES) self._roughness = rough @property def thermal_absorptance(self): """Get or set the thermal absorptance of the material layer.""" 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, 'material thermal absorptance') @property def solar_absorptance(self): """Get or set the solar absorptance of the material layer.""" 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, 'material solar absorptance') @property def visible_absorptance(self): """Get or set the visible absorptance of the material layer.""" 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, 'material visible absorptance') if v_abs is not None \ else None @property def solar_reflectance(self): """Get or set the front solar reflectance of the material layer.""" 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, 'material solar reflectance') self.solar_absorptance = 1 - v_ref @property def visible_reflectance(self): """Get or set the front visible reflectance of the material layer.""" 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, 'material visible reflectance') self.visible_absorptance = 1 - v_ref @property def thickness(self): """Returns 0 for the thickness of a no mass material.""" return 0 @property def mass_area_density(self): """Returns 0 for the area density of a no mass material.""" return 0 @property def area_heat_capacity(self): """Returns 0 for the heat capacity of a no mass material.""" return 0
[docs] @classmethod def from_idf(cls, idf_string): """Create an EnergyMaterialNoMass from an EnergyPlus text string. Args: idf_string: A text string fully describing an EnergyPlus material. """ ep_strs = parse_idf_string(idf_string, 'Material:NoMass,') idf_defaults = {3: 0.9, 4: 0.7, 5: 0.7} for i, ep_str in enumerate(ep_strs): # fill in any default values if ep_str == '' and i in idf_defaults: ep_strs[i] = idf_defaults[i] ep_strs.insert(2, ep_strs.pop(1)) # move roughness to correct place return cls(*ep_strs)
[docs] @classmethod def from_idf_air_gap(cls, idf_string): """Create an EnergyMaterialNoMass from an EnergyPlus string of an AirGap. Args: idf_string: A text string fully describing an EnergyPlus Material:AirGap. """ ep_strs = parse_idf_string(idf_string, 'Material:AirGap,') return cls(*ep_strs)
[docs] @classmethod def from_dict(cls, data): """Create a EnergyMaterialNoMass from a dictionary. Args: data: A python dictionary in the following format .. code-block:: python { "type": 'EnergyMaterialNoMass', "identifier": 'Insulation_R20_MediumRough_090_070_070', "display_name": 'Insulation R2', "r_value": 2.0, "roughness": 'MediumRough', "thermal_absorptance": 0.9, "solar_absorptance": 0.7, "visible_absorptance": 0.7 } """ assert data['type'] == 'EnergyMaterialNoMass', \ 'Expected EnergyMaterialNoMass. Got {}.'.format(data['type']) rough = data['roughness'] if 'roughness' in data and \ data['roughness'] is not None else 'MediumRough' 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['r_value'], rough, 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 material. ..code-block:: shell Material:NoMass, R13LAYER, ! Material Name Rough, ! Roughness 2.290965, ! Resistance {M**2K/W} 0.9000000, ! Thermal Absorptance 0.7500000, ! Solar Absorptance 0.7500000; ! Visible Absorptance """ values = ( self.identifier, self.roughness, self.r_value, self.thermal_absorptance, self.solar_absorptance, self.visible_absorptance ) comments = ('name', 'roughness', 'r-value {m2-K/W}', 'thermal absorptance', 'solar absorptance', 'visible absorptance') return generate_idf_string('Material:NoMass', values, comments)
[docs] def to_radiance_solar(self, specularity=0.0): """Honeybee Radiance material from the solar reflectance of this material.""" try: from honeybee_radiance.modifier.material import Plastic except ImportError as e: raise ImportError('honeybee_radiance library must be installed to use ' 'to_radiance_solar() method. {}'.format(e)) return Plastic.from_single_reflectance( clean_rad_string(self.identifier), 1 - self.solar_absorptance, specularity, self.RADIANCEROUGHTYPES[self.roughness])
[docs] def to_radiance_visible(self, specularity=0.0): """Honeybee Radiance material from the visible reflectance of this material.""" try: from honeybee_radiance.modifier.material import Plastic except ImportError as e: raise ImportError('honeybee_radiance library must be installed to use ' 'to_radiance_solar() method. {}'.format(e)) return Plastic.from_single_reflectance( clean_rad_string(self.identifier), 1 - self.visible_absorptance, specularity, self.RADIANCEROUGHTYPES[self.roughness])
[docs] def to_dict(self): """Energy Material No Mass dictionary representation.""" base = { 'type': 'EnergyMaterialNoMass', 'identifier': self.identifier, 'r_value': self.r_value, 'roughness': self.roughness, '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): return (self.identifier, self.r_value, self.roughness, self.thermal_absorptance, self.solar_absorptance, self.visible_absorptance) def __hash__(self): """A small tuple based on the object properties, useful for hashing.""" return hash(self.__key()) def __eq__(self, other): return isinstance(other, EnergyMaterialNoMass) 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.r_value, self.roughness, 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
[docs] @lockable class EnergyMaterialVegetation(_EnergyMaterialOpaqueBase): """EnergyPlus Material:RoofVegetation 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. thickness: Number for the thickness of the soil layer [m]. (Default: 0.1). conductivity: Number for the thermal conductivity of the dry soil [W/m-K]. (Default: 0.35). density: Number for the density of the dry soil [kg/m3]. (Default: 1100). specific_heat: Number for the specific heat of the soil [J/kg-K]. (Default: 1200) roughness: Text describing the relative roughness of the soil material. (Default: MediumRough). Must be one of the following: * VeryRough * Rough * MediumRough * MediumSmooth * Smooth * VerySmooth soil_thermal_absorptance: A number between 0 and 1 for the fraction of incident long wavelength radiation that is absorbed by the soil material. (Default: 0.9). soil_solar_absorptance: A number between 0 and 1 for the fraction of incident solar radiation absorbed by the soil material. (Default: 0.7). soil_visible_absorptance: A number between 0 and 1 for the fraction of incident visible wavelength radiation absorbed by the soil material. Default is None, which will yield the same value as soil_solar_absorptance. plant_height: A number between 0.005 and 1.0 for the height of plants in the vegetation layer [m]. (Default: 0.2 m). leaf_area_index: A number between 0.001 and 5.0 for the projected leaf area per unit area of soil surface (aka. Leaf Area Index or LAI). Note that the fraction of vegetation cover is calculated directly from LAI using an empirical relation. (Default: 1.0). leaf_reflectivity: A number between 0.05 and 0.5 for the fraction of incident solar radiation that is reflected by the leaf surfaces. Solar radiation includes the visible spectrum as well as infrared and ultraviolet wavelengths. Typical values are 0.18 to 0.25. (Default: 0.22). leaf_emissivity: A number between 0.8 and 1.0 for the ratio of thermal radiation emitted from leaf surfaces to that emitted by an ideal black body at the same temperature. (Default: 0.95). min_stomatal_resist: A number between 50 and 300 for the resistance of the plants to moisture transport [s/m]. Plants with low values of stomatal resistance will result in higher evapotranspiration rates than plants with high resistance. (Default: 180). Properties: * identifier * display_name * roughness * thickness * conductivity * density * specific_heat * soil_thermal_absorptance * soil_solar_absorptance * soil_visible_absorptance * plant_height * leaf_area_index * leaf_reflectivity * leaf_emissivity * min_stomatal_resist * sat_vol_moist_cont * residual_vol_moist_cont * init_vol_moist_cont * moist_diff_model * soil_layer * thermal_absorptance * solar_absorptance * visible_absorptance * solar_reflectance * visible_reflectance * resistivity * u_value * r_value * mass_area_density * area_heat_capacity * user_data * properties """ __slots__ = ( '_thickness', '_conductivity', '_density', '_specific_heat', '_roughness', '_soil_thermal_absorptance', '_soil_solar_absorptance', '_soil_visible_absorptance', '_plant_height', '_leaf_area_index', '_leaf_reflectivity', '_leaf_emissivity', '_min_stomatal_resist', '_sat_vol_moist_cont', '_residual_vol_moist_cont', '_init_vol_moist_cont', '_moist_diff_model' ) DIFFTYPES = ('Simple', 'Advanced') def __init__( self, identifier, thickness=0.1, conductivity=0.35, density=1100, specific_heat=1200, roughness='MediumRough', soil_thermal_absorptance=0.9, soil_solar_absorptance=0.7, soil_visible_absorptance=None, plant_height=0.2, leaf_area_index=1.0, leaf_reflectivity=0.22, leaf_emissivity=0.95, min_stomatal_resist=180 ): # set the properties from the init arguments _EnergyMaterialOpaqueBase.__init__(self, identifier) self.thickness = thickness self.conductivity = conductivity self.density = density self.specific_heat = specific_heat self.roughness = roughness self.soil_thermal_absorptance = soil_thermal_absorptance self.soil_solar_absorptance = soil_solar_absorptance self.soil_visible_absorptance = soil_visible_absorptance self.plant_height = plant_height self.leaf_area_index = leaf_area_index self.leaf_reflectivity = leaf_reflectivity self.leaf_emissivity = leaf_emissivity self.min_stomatal_resist = min_stomatal_resist # set some basic defaults for everything else self._sat_vol_moist_cont = 0.3 self._residual_vol_moist_cont = 0.01 self._init_vol_moist_cont = 0.1 self._moist_diff_model = 'Simple' self._locked = False self._properties = EnergyMaterialVegetationProperties(self) @property def roughness(self): """Get or set the text describing the roughness of the soil material layer.""" return self._roughness @roughness.setter def roughness(self, rough): assert rough in self.ROUGHTYPES, 'Invalid input "{}" for material roughness.' \ ' Roughness must be one of the following:\n{}'.format(rough, self.ROUGHTYPES) self._roughness = rough @property def thickness(self): """Get or set the thickness of the soil material layer [m].""" return self._thickness @thickness.setter def thickness(self, thick): self._thickness = float_positive(thick, 'material thickness') assert self._thickness != 0, 'Material thickness must be greater than zero.' @property def conductivity(self): """Get or set the conductivity of the soil material layer [W/m-K].""" return self._conductivity @conductivity.setter def conductivity(self, cond): self._conductivity = float_positive(cond, 'material conductivity') @property def density(self): """Get or set the density of the soil material layer [kg/m3].""" return self._density @density.setter def density(self, dens): self._density = float_positive(dens, 'material density') @property def specific_heat(self): """Get or set the specific heat of the soil material layer [J/kg-K].""" return self._specific_heat @specific_heat.setter def specific_heat(self, sp_ht): self._specific_heat = float_in_range( sp_ht, 100.0, input_name='material specific heat') @property def soil_thermal_absorptance(self): """Get or set the thermal absorptance of the soil material layer.""" return self._soil_thermal_absorptance @soil_thermal_absorptance.setter def soil_thermal_absorptance(self, t_abs): self._soil_thermal_absorptance = float_in_range( t_abs, 0.0, 1.0, 'material thermal absorptance') @property def soil_solar_absorptance(self): """Get or set the solar absorptance of the soil material layer.""" return self._soil_solar_absorptance @soil_solar_absorptance.setter def soil_solar_absorptance(self, s_abs): self._soil_solar_absorptance = float_in_range( s_abs, 0.0, 1.0, 'material solar absorptance') @property def soil_visible_absorptance(self): """Get or set the visible absorptance of the soil material layer.""" return self._soil_visible_absorptance if self._soil_visible_absorptance \ is not None else self._soil_solar_absorptance @soil_visible_absorptance.setter def soil_visible_absorptance(self, v_abs): self._soil_visible_absorptance = float_in_range( v_abs, 0.0, 1.0, 'material visible absorptance') \ if v_abs is not None else None @property def plant_height(self): """Get or set a number for the height of plants in the vegetation layer [m].""" return self._plant_height @plant_height.setter def plant_height(self, p_h): self._plant_height = float_in_range(p_h, 0.005, 1.000, 'plant height') @property def leaf_area_index(self): """Get or set a number for the leaf area per unit area of soil surface.""" return self._leaf_area_index @leaf_area_index.setter def leaf_area_index(self, lai): self._leaf_area_index = float_in_range(lai, 0.001, 5.00, 'leaf area index') @property def leaf_reflectivity(self): """Get or set a number for the solar reflectivity of the leaf surfaces.""" return self._leaf_reflectivity @leaf_reflectivity.setter def leaf_reflectivity(self, l_r): self._leaf_reflectivity = float_in_range(l_r, 0.05, 0.50, 'leaf reflectivity') @property def leaf_emissivity(self): """Get or set a number for the emissivity of the leaf surfaces.""" return self._leaf_emissivity @leaf_emissivity.setter def leaf_emissivity(self, l_e): self._leaf_emissivity = float_in_range(l_e, 0.8, 1.0) @property def min_stomatal_resist(self): """Get or set a number for the resistance of the plants to moisture [s/m].""" return self._min_stomatal_resist @min_stomatal_resist.setter def min_stomatal_resist(self, msr): self._min_stomatal_resist = float_in_range( msr, 50.0, 300.0, 'minimum stomatal resistance') @property def sat_vol_moist_cont(self): """Get or set a number for the for the saturation moisture content of the soil. The number must be between 0.1 and 0.5. (Default: 0.3). """ return self._sat_vol_moist_cont @sat_vol_moist_cont.setter def sat_vol_moist_cont(self, s_vmc): self._sat_vol_moist_cont = float_in_range( s_vmc, 0.1, 0.5, 'saturation moisture content of soil layer') @property def residual_vol_moist_cont(self): """Get or set a number for the for the residual moisture content of the soil. The number must be between 0.01 and 0.1. (Default: .01). """ return self._residual_vol_moist_cont @residual_vol_moist_cont.setter def residual_vol_moist_cont(self, r_vmc): self._residual_vol_moist_cont = float_in_range( r_vmc, 0.01, 0.1, 'residual moisture content of soil layer') @property def init_vol_moist_cont(self): """Get or set a number for the for the initial moisture content of the soil. The number must be between 0.05 and 0.5. (Default: .01). """ return self._init_vol_moist_cont @init_vol_moist_cont.setter def init_vol_moist_cont(self, i_vmc): self._init_vol_moist_cont = float_in_range( i_vmc, 0.05, 0.50, 'initial moisture content of soil layer') @property def moist_diff_model(self): """Get or set text for the moisture diffusion model to use. Note that the Advanced model should be run with simulation parameters of 20 timesteps per hour. (Default: Simple). Choose from the following: * Simple * Advanced """ return self._moist_diff_model @moist_diff_model.setter def moist_diff_model(self, mdc): assert mdc in self.DIFFTYPES, 'Invalid input "{}" for moisture diffusion ' \ 'model. Must be one of the following:\n{}'.format(mdc, self.DIFFTYPES) self._moist_diff_model = mdc @property def soil_layer(self): """Get an EnergyMaterial representing only the soil.""" return EnergyMaterial( '{}_Soil'.format(self.identifier), self.thickness, self.conductivity, self.density, self.specific_heat, self.roughness, self.soil_thermal_absorptance, self.soil_solar_absorptance, self.soil_visible_absorptance) @property def thermal_absorptance(self): """Get the thermal absorptance including soil and vegetation.""" return self._leaf_emissivity if self._leaf_area_index >= 1 else \ (self._leaf_emissivity * self._leaf_area_index) + \ (self._soil_thermal_absorptance * (1 - self._leaf_area_index)) @property def solar_absorptance(self): """Get the solar absorptance including soil and vegetation.""" return 1 - self._leaf_reflectivity if self._leaf_area_index >= 1 else \ ((1 - self._leaf_reflectivity) * self._leaf_area_index) + \ (self._soil_solar_absorptance * (1 - self._leaf_area_index)) @property def visible_absorptance(self): """Get the visible absorptance including soil and vegetation.""" s_vis = self._soil_visible_absorptance if self._soil_visible_absorptance \ is not None else self._soil_solar_absorptance return 1 - self._leaf_reflectivity if self._leaf_area_index >= 1 else \ ((1 - self._leaf_reflectivity) * self._leaf_area_index) + \ (s_vis * (1 - self._leaf_area_index)) @property def solar_reflectance(self): """Get the solar reflectance including soil and vegetation.""" return 1 - self.solar_absorptance @property def visible_reflectance(self): """Get the visible reflectance including soil and vegetation.""" return 1 - self.visible_absorptance @property def resistivity(self): """Get or set the resistivity of the material layer [m-K/W].""" return 1 / self._conductivity @resistivity.setter def resistivity(self, resis): self._conductivity = 1 / float_positive(resis, 'material resistivity') @property def r_value(self): """Get or set the R-value of the material in [m2-K/W] (excluding air films). Note that, when setting the R-value, the thickness of the material will remain fixed and only the conductivity will be adjusted. """ return self.thickness / self.conductivity @r_value.setter def r_value(self, r_val): _new_conductivity = self.thickness / float_positive(r_val, 'material r-value') self._conductivity = _new_conductivity @property def u_value(self): """Get or set the U-value of the material [W/m2-K] (excluding air films). Note that, when setting the R-value, the thickness of the material will remain fixed and only the conductivity will be adjusted. """ return self.conductivity / self.thickness @u_value.setter def u_value(self, u_val): self.r_value = 1 / float_positive(u_val, 'material u-value') @property def mass_area_density(self): """The area density of the material [kg/m2].""" return self.thickness * self.density @property def area_heat_capacity(self): """The heat capacity per unit area of the material [J/K-m2].""" return self.mass_area_density * self.specific_heat
[docs] @classmethod def from_idf(cls, idf_string): """Create an EnergyMaterial from an EnergyPlus text string. Args: idf_string: A text string fully describing an EnergyPlus roof vegetation material. """ ep_strs = parse_idf_string(idf_string, 'Material:RoofVegetation') vals = [None, 0.2, 1, 0.22, 0.95, 180, None, 'MediumRough', 0.1, 0.35, 1100, 1200, 0.9, 0.7, 0.75, 0.3, 0.01, 0.1, 'Advanced'] for i, ep_str in enumerate(ep_strs): # fill in any default values if ep_str != '': vals[i] = ep_str mat = cls(vals[0], vals[8], vals[9], vals[10], vals[11], vals[7], vals[12], vals[13], vals[14], vals[1], vals[2], vals[3], vals[4], vals[5]) mat.sat_vol_moist_cont = vals[15] mat.residual_vol_moist_cont = vals[16] mat.init_vol_moist_cont = vals[17] mat.moist_diff_model = vals[18] return mat
[docs] @classmethod def from_dict(cls, data): """Create an EnergyMaterialVegetation from a dictionary. Args: data: A python dictionary in the following format .. code-block:: python { 'type': 'EnergyMaterialVegetation', 'identifier': 'Green_Roof_040_110_7868_987', 'plant_height': 0.9, 'leaf_area_index': 1.0, 'leaf_reflectivity': 0.22, 'leaf_emissivity': 0.95, 'min_stomatal_resist': 180, 'soil_layer_name': 'GreenRoofSoil, 'roughness': 'MediumRough, 'thickness':0.1, 'conductivity': 0.35, 'density': 1100, 'specific_heat': 800, 'soil_thermal_absorptance': 0.9, 'soil_solar_absorptance': 0.7, 'soil_visible_absorptance':0.7, 'sat_vol_moist_cont': 0.3, 'residual_vol_moist_cont': 0.01, 'init_vol_moist_cont': 0.1, 'moist_diff_model': 'Simple' } """ assert data['type'] == 'EnergyMaterialVegetation', \ 'Expected EnergyMaterialVegetation. Got {}'.format(data['type']) rough = data['roughness'] if 'roughness' in data and \ data['roughness'] is not None else 'MediumRough' thick = data['thickness'] if 'thickness' in data and \ data['thickness'] is not None else 0.1 t_abs = data['soil_thermal_absorptance'] if 'soil_thermal_absorptance' in data \ and data['soil_thermal_absorptance'] is not None else 0.9 s_abs = data['soil_solar_absorptance'] if 'soil_solar_absorptance' in data \ and data['soil_solar_absorptance'] is not None else 0.7 v_abs = data['soil_visible_absorptance'] \ if 'soil_visible_absorptance' in data else None cond = data['conductivity'] if 'conductivity' in data and \ data['conductivity'] is not None else 0.35 dens = data['density'] if 'density' in data and \ data['density'] is not None else 1100 sp_ht = data['specific_heat'] if 'specific_heat' in data and \ data['specific_heat'] is not None else 1200 p_h = data['plant_height'] if 'plant_height' in data and \ data['plant_height'] is not None else 0.2 lai = data['leaf_area_index'] if 'leaf_area_index' in data and \ data['leaf_area_index'] is not None else 1.0 l_r = data['leaf_reflectivity'] if 'leaf_reflectivity' in data and \ data['leaf_reflectivity'] is not None else 0.22 l_e = data['leaf_emissivity'] if 'leaf_emissivity' in data and \ data['leaf_emissivity'] is not None else 0.95 msr = data['min_stomatal_resist'] if 'min_stomatal_resist' in data and \ data['min_stomatal_resist'] is not None else 180 s_vmc = data['sat_vol_moist_cont'] if 'sat_vol_moist_cont' \ in data and data['sat_vol_moist_cont'] is not None else 0.3 r_vmc = data['residual_vol_moist_cont'] if 'residual_vol_moist_cont' \ in data and data['residual_vol_moist_cont'] is not None else 0.01 i_vmc = data['init_vol_moist_cont'] if 'init_vol_moist_cont' \ in data and data['init_vol_moist_cont'] is not None else 0.1 mdc = data['moist_diff_model'] if 'moist_diff_model' in data and \ data['moist_diff_model'] is not None else 'Simple' new_mat = cls( data['identifier'], thick, cond, dens, sp_ht, rough, t_abs, s_abs, v_abs, p_h, lai, l_r, l_e, msr) new_mat.sat_vol_moist_cont = s_vmc new_mat.residual_vol_moist_cont = r_vmc new_mat.init_vol_moist_cont = i_vmc new_mat.moist_diff_model = mdc 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_radiance_solar(self, specularity=0.0): """Honeybee Radiance material from the solar reflectance of this material.""" try: from honeybee_radiance.modifier.material import Plastic except ImportError as e: raise ImportError('honeybee_radiance library must be installed to use ' 'to_radiance_solar() method. {}'.format(e)) return Plastic.from_single_reflectance( clean_rad_string(self.identifier), self.solar_reflectance, specularity, self.RADIANCEROUGHTYPES[self.roughness])
[docs] def to_radiance_visible(self, specularity=0.0): """Honeybee Radiance material from the visible reflectance of this material.""" try: from honeybee_radiance.modifier.material import Plastic except ImportError as e: raise ImportError('honeybee_radiance library must be installed to use ' 'to_radiance_solar() method. {}'.format(e)) return Plastic.from_single_reflectance( clean_rad_string(self.identifier), self.visible_reflectance, specularity, self.RADIANCEROUGHTYPES[self.roughness])
[docs] def to_idf(self): """Get an EnergyPlus string representation of the material. .. code-block:: shell Material:RoofVegetation, BaseEco, !- Name 0.5, !- Height of Plants {m} 5, !- Leaf Area Index {dimensionless} 0.2, !- Leaf Reflectivity {dimensionless} 0.95, !- Leaf Emissivity 180, !- Minimum Stomatal Resistance {s/m} EcoRoofSoil, !- Soil Layer Name MediumSmooth, !- Roughness 0.18, !- Thickness {m} 0.4, !- Conductivity of Dry Soil {W/m-K} 641, !- Density of Dry Soil {kg/m3} 1100, !- Specific Heat of Dry Soil {J/kg-K} 0.95, !- Thermal Absorptance 0.8, !- Solar Absorptance 0.7, !- Visible Absorptance 0.4, !- Saturation Volumetric Moisture Content of the Soil Layer 0.01, !- Residual Volumetric Moisture Content of the Soil Layer 0.2, !- Initial Volumetric Moisture Content of the Soil Layer Simple; !- Moisture Diffusion Calculation Method """ soil_name = '{}_SoilLayer'.format(self.identifier) values = ( self.identifier, self.plant_height, self.leaf_area_index, self.leaf_reflectivity, self.leaf_emissivity, self.min_stomatal_resist, soil_name, self.roughness, self.thickness, self.conductivity, self.density, self.specific_heat, self.soil_thermal_absorptance, self.soil_solar_absorptance, self.soil_visible_absorptance, self.sat_vol_moist_cont, self.residual_vol_moist_cont, self.init_vol_moist_cont, self.moist_diff_model ) comments = ( 'name', 'height of plants', 'leaf area index', 'leaf reflectivity', 'leaf emissivity', 'minimum stomatal resistance', 'soil layer name', 'roughness', 'thickness', 'conductivity of dry soil', 'density of dry soil', 'specific heat of dry soil', 'soil thermal absorptance', 'soil solar absorptance', 'soil visible absorptance', 'saturation volumetric moisture content of soil', 'residual volumetric moisture content of soil', 'initial volumetric moisture content of soil', 'moisture diffusion calculation method' ) return generate_idf_string('Material:RoofVegetation', values, comments)
[docs] def to_dict(self): base = { 'type': 'EnergyMaterialVegetation', 'identifier': self.identifier, 'plant_height': self.plant_height, 'leaf_area_index': self.leaf_area_index, 'leaf_reflectivity': self.leaf_reflectivity, 'leaf_emissivity': self.leaf_emissivity, 'min_stomatal_resist': self.min_stomatal_resist, 'roughness': self.roughness, 'thickness': self.thickness, 'conductivity': self.conductivity, 'density': self.density, 'specific_heat': self.specific_heat, 'soil_thermal_absorptance': self.soil_thermal_absorptance, 'soil_solar_absorptance': self.soil_solar_absorptance, 'soil_visible_absorptance': self.soil_visible_absorptance, 'sat_vol_moist_cont': self.sat_vol_moist_cont, 'residual_vol_moist_cont': self.residual_vol_moist_cont, 'init_vol_moist_cont': self.init_vol_moist_cont, 'moist_diff_model': self.moist_diff_model } 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.plant_height, self.leaf_area_index, self.leaf_reflectivity, self.leaf_emissivity, self.min_stomatal_resist, self.roughness, self.thickness, self.conductivity, self.density, self.specific_heat, self.soil_thermal_absorptance, self.soil_solar_absorptance, self.soil_visible_absorptance, self.sat_vol_moist_cont, self.residual_vol_moist_cont, self.init_vol_moist_cont, self.moist_diff_model) def __hash__(self): return hash(self.__key()) def __eq__(self, other): return isinstance(other, EnergyMaterialVegetation) \ 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 = EnergyMaterialVegetation( self.identifier, self.thickness, self.conductivity, self.density, self.specific_heat, self.roughness, self.soil_thermal_absorptance, self.soil_solar_absorptance, self.soil_visible_absorptance, self.plant_height, self.leaf_area_index, self.leaf_reflectivity, self.leaf_emissivity, self.min_stomatal_resist) new_material._sat_vol_moist_cont = self._sat_vol_moist_cont new_material._residual_vol_moist_cont = self._residual_vol_moist_cont new_material._init_vol_moist_cont = self._init_vol_moist_cont new_material._moist_diff_model = self._moist_diff_model 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