Source code for honeybee_energy.internalmass

# coding=utf-8
"""Room internal mass, including construction and surface area."""
from __future__ import division

from honeybee._lockable import lockable
from honeybee.typing import valid_ep_string, float_positive
from honeybee.units import conversion_factor_to_meters

from .construction.opaque import OpaqueConstruction
from .material.opaque import EnergyMaterialVegetation
from .reader import parse_idf_string
from .writer import generate_idf_string


[docs] @lockable class InternalMass(object): """Room internal mass, including construction and surface area. Note that internal masses assigned this way cannot "see" solar radiation that may potentially hit them and, as such, caution should be taken when using this component with internal mass objects that are not always in shade. Masses are factored into the the thermal calculations of the Room by undergoing heat transfer with the indoor air. Args: identifier: Text string for a unique InternalMass 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. construction: An OpaqueConstruction object that represents the material that the internal thermal mass is composed of. area: A number representing the surface area of the internal mass that is exposed to the Room air. This value should always be in square meters regardless of what units system the parent model is a part of. Properties: * identifier * display_name * construction * area * user_data """ __slots__ = ('_identifier', '_display_name', '_construction', '_area', '_locked', '_user_data') def __init__(self, identifier, construction, area): self._locked = False # unlocked by default self.identifier = identifier self._display_name = None self.construction = construction self.area = area self._user_data = None @property def identifier(self): """Get or set the text string for object identifier.""" return self._identifier @identifier.setter def identifier(self, identifier): self._identifier = valid_ep_string(identifier) @property def display_name(self): """Get or set a string for the object name without any character restrictions. If not set, this will be equal to the identifier. """ if self._display_name is None: return self._identifier return self._display_name @display_name.setter def display_name(self, value): if value is not None: try: value = str(value) except UnicodeEncodeError: # Python 2 machine lacking the character set pass # keep it as unicode self._display_name = value @property def construction(self): """Get or set a Construction for the material the internal mass is composed of. """ return self._construction @construction.setter def construction(self, value): assert isinstance(value, OpaqueConstruction), \ 'Expected Opaque Construction for InternalMass. Got {}'.format(type(value)) assert not isinstance(value.materials[0], EnergyMaterialVegetation), \ 'InternalMass constructions cannot contain vegetation materials' value.lock() # lock editing in case construction has multiple references self._construction = value @property def area(self): """Get or set a number for the surface area of the mass exposed to the Room air. """ return self._area @area.setter def area(self, value): self._area = float_positive(value, 'internal mass area') @property def user_data(self): """Get or set an optional dictionary for additional meta data for this object. This will be None until it has been set. All keys and values of this dictionary should be of a standard Python type to ensure correct serialization of the object to/from JSON (eg. str, float, int, list, dict) """ if self._user_data is not None: return self._user_data @user_data.setter def user_data(self, value): if value is not None: assert isinstance(value, dict), 'Expected dictionary for honeybee_energy' \ 'object user_data. Got {}.'.format(type(value)) self._user_data = value
[docs] @classmethod def from_geometry(cls, identifier, construction, geometry, units='Meters'): """Create an InternalMass object from a list of geometries. Args: identifier: Text string for a unique InternalMass 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. construction: An OpaqueConstruction object that represents the material that the internal thermal mass is composed of. geometry: An array of Face3D representing the exposed surface of the internal mass. Note that these Face3D are assumed to be one-sided so, if they are meant to represent a 2-sided object, the Face3D should be duplicated and offset. units: Text for the units system of the geometry. Choose from the following: * Meters * Millimeters * Feet * Inches * Centimeters """ area = sum(geo.area for geo in geometry) * conversion_factor_to_meters(units) return cls(identifier, construction, area)
[docs] @classmethod def from_idf(cls, idf_string, construction_dict): """Create an InternalMass object from an EnergyPlus IDF text string. Args: idf_string: A text string fully describing an EnergyPlus InternalMass definition. construction_dict: A dictionary with construction identifiers as keys and honeybee construction objects as values. This will be used to assign the construction to the InternalMass object. Returns: An InternalMass object loaded from the idf_string. """ ep_strs = parse_idf_string(idf_string, 'InternalMass,') obj_id = ep_strs[0].split('..')[0] return cls(obj_id, construction_dict[ep_strs[1]], ep_strs[4])
[docs] @classmethod def from_dict(cls, data): """Create an InternalMass object from a dictionary. Note that the dictionary must be a non-abridged version for this classmethod to work. Args: data: An InternalMass dictionary in following the format below. .. code-block:: python { "type": 'InternalMass', "identifier": 'Kitchen_Table_Wood_050', "display_name": 'Kitchen Table', "construction": {}, # OpaqueConstruction definition "area": 5 # surface area of internal mass in square meters } """ assert data['type'] == 'InternalMass', \ 'Expected InternalMass dictionary. Got {}.'.format(data['type']) constr = OpaqueConstruction.from_dict(data['construction']) new_obj = cls(data['identifier'], constr, data['area']) if 'display_name' in data and data['display_name'] is not None: new_obj.display_name = data['display_name'] if 'user_data' in data and data['user_data'] is not None: new_obj.user_data = data['user_data'] return new_obj
[docs] @classmethod def from_dict_abridged(cls, data, construction_dict): """Create a InternalMass from an abridged dictionary. Args: data: An InternalMassAbridged dictionary. construction_dict: A dictionary with construction identifiers as keys and honeybee construction objects as values. This will be used to assign the construction to the InternalMass object. .. code-block:: python { "type": 'InternalMassAbridged', "identifier": 'Kitchen_Table_Wood_050', "display_name": 'Kitchen Table', "construction": 'Hardwood_050' # OpaqueConstruction identifier "area": 5 # surface area of internal mass in square meters } """ assert data['type'] == 'InternalMassAbridged', \ 'Expected InternalMassAbridged dictionary. Got {}.'.format(data['type']) new_obj = cls( data['identifier'], construction_dict[data['construction']], data['area']) if 'display_name' in data and data['display_name'] is not None: new_obj.display_name = data['display_name'] if 'user_data' in data and data['user_data'] is not None: new_obj.user_data = data['user_data'] return new_obj
[docs] def to_idf(self, zone_identifier): """IDF string representation of InternalMass object. Note that this method only outputs a single string for the InternalMass object and, to write everything needed to describe the object into an IDF, this object's construction must also be written. Args: zone_identifier: Text for the zone identifier that the InternalMass object is assigned to. .. code-block:: shell InternalMass, Zn002:IntM001, !- Surface Name INTERIOR, !- Construction Name DORM ROOMS AND COMMON AREAS, !- Zone or ZoneList Name 408.7734; !- Total area exposed to Zone {m2} """ values = ('{}..{}'.format(self.identifier, zone_identifier), self.construction.identifier, zone_identifier, '', self.area) comments = ('name', 'construction name', 'zone name', 'space name', 'surface area') return generate_idf_string('InternalMass', values, comments)
[docs] def to_dict(self, abridged=False): """InternalMass dictionary representation. Args: abridged: Boolean to note whether the full dictionary describing the object should be returned (False) or just an abridged version (True), which only specifies the identifiers of the construction. (Default: False). """ base = {'type': 'InternalMass'} if not abridged \ else {'type': 'InternalMassAbridged'} base['identifier'] = self.identifier base['construction'] = self.construction.to_dict() if not \ abridged else self.construction.identifier base['area'] = self.area 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 return base
[docs] def duplicate(self): """Get a copy of this object.""" return self.__copy__()
def __copy__(self): new_obj = InternalMass(self.identifier, self.construction, self.area) new_obj._display_name = self._display_name new_obj._user_data = None if self._user_data is None else self._user_data.copy() return new_obj def __key(self): """A tuple based on the object properties, useful for hashing.""" return (self.identifier, hash(self.construction), self.area) def __hash__(self): return hash(self.__key()) def __eq__(self, other): return isinstance(other, InternalMass) and self.__key() == other.__key() def __ne__(self, other): return not self.__eq__(other)
[docs] def ToString(self): """Overwrite .NET ToString.""" return self.__repr__()
def __repr__(self): return 'InternalMass: {}'.format(self.display_name)