Source code for honeybee_doe2.properties.room

# coding=utf-8
"""Room DOE-2 Properties."""
import math

from ladybug_geometry.geometry3d import Face3D
from honeybee.typing import float_in_range, float_positive
from honeybee.altnumber import autocalculate

from ..load import MECH_AIRFLOW_KEYS


[docs] class RoomDoe2Properties(object): """DOE-2 Properties for Honeybee Room. Args: host: A honeybee_core Room object that hosts these properties. assigned_flow: A number for the design supply air flow rate for the zone the Room is assigned to (cfm). This establishes the minimum allowed design air flow. Note that the actual design flow may be larger. If None, this parameter will not be written into the INP. (Default: None). flow_per_area: A number for the design supply air flow rate to the zone per unit floor area (cfm/ft2). If None, this parameter will not be written into the INP. (Default: None). min_flow_ratio: A number between 0 and 1 for the minimum allowable zone air supply flow rate, expressed as a fraction of design flow rate. Applicable to variable-volume type systems only. If None, this parameter will not be written into the INP. (Default: None). min_flow_per_area: A number for the minimum air flow per square foot of floor area (cfm/ft2). This is an alternative way of specifying the min_flow_ratio. If None, this parameter will not be written into the INP. (Default: None). hmax_flow_ratio: A number between 0 and 1 for the ratio of the maximum (or fixed) heating airflow to the cooling airflow. The specific meaning varies according to the type of zone terminal. If None, this parameter will not be written into the INP. (Default: None). space_polygon_geometry: An optional horizontal Face3D object, which will be used to set the SPACE polygon during export to INP. If None, the SPACE polygon is auto-calculated from the 3D Room geometry. Specifying a geometry here can help overcome some limitations of this auto-calculation, particularly for cases where the floors of the Room are composed of AirBoundaries. (Default: None). Properties: * host * assigned_flow * flow_per_area * min_flow_ratio * min_flow_per_area * hmax_flow_ratio * space_polygon_geometry """ __slots__ = ( '_host', '_assigned_flow', '_flow_per_area', '_min_flow_ratio', '_min_flow_per_area', '_hmax_flow_ratio', '_space_polygon_geometry' ) def __init__( self, host, assigned_flow=None, flow_per_area=None, min_flow_ratio=None, min_flow_per_area=None, hmax_flow_ratio=None, space_polygon_geometry=None ): """Initialize Room DOE-2 properties.""" # set the main properties of the Room self._host = host self.assigned_flow = assigned_flow self.flow_per_area = flow_per_area self.min_flow_ratio = min_flow_ratio self.min_flow_per_area = min_flow_per_area self.hmax_flow_ratio = hmax_flow_ratio self.space_polygon_geometry = space_polygon_geometry @property def host(self): """Get the Room object hosting these properties.""" return self._host @property def assigned_flow(self): """Get or set the design supply air flow rate for the zone (cfm).""" return self._assigned_flow @assigned_flow.setter def assigned_flow(self, value): if value is not None: value = float_positive(value, 'zone assigned flow') self._assigned_flow = value @property def flow_per_area(self): """Get or set the design supply air flow rate per unit floor area (cfm/ft2). """ return self._flow_per_area @flow_per_area.setter def flow_per_area(self, value): if value is not None: value = float_positive(value, 'zone flow per area') self._flow_per_area = value @property def min_flow_ratio(self): """Get or set the the min supply airflow rate as a fraction of design flow rate. """ return self._min_flow_ratio @min_flow_ratio.setter def min_flow_ratio(self, value): if value is not None: value = float_in_range(value, 0.0, 1.0, 'zone min flow ratio') self._min_flow_ratio = value @property def min_flow_per_area(self): """Get or set the minimum air flow per square foot of floor area (cfm/ft2).""" return self._min_flow_per_area @min_flow_per_area.setter def min_flow_per_area(self, value): if value is not None: value = float_positive(value, 'zone min flow per area') self._min_flow_per_area = value @property def hmax_flow_ratio(self): """Get or set the ratio of the maximum heating airflow to the cooling airflow. """ return self._hmax_flow_ratio @hmax_flow_ratio.setter def hmax_flow_ratio(self, value): if value is not None: value = float_in_range(value, 0.0, 1.0, 'zone heating max flow ratio') self._hmax_flow_ratio = value @property def space_polygon_geometry(self): """Get or set a horizontal Face3D to set the space polygon geometry.""" return self._space_polygon_geometry @space_polygon_geometry.setter def space_polygon_geometry(self, value): if value is not None: assert isinstance(value, Face3D), \ 'Expected ladybug_geometry Face3D. Got {}'.format(type(value)) if value.normal.z < 0: # ensure upward-facing Face3D self._floor_geometry = value.flip() self._space_polygon_geometry = value
[docs] def move(self, moving_vec): """Move this object along a vector. Args: moving_vec: A ladybug_geometry Vector3D with the direction and distance to move the object. """ if self.space_polygon_geometry is not None: self._space_polygon_geometry = self.space_polygon_geometry.move(moving_vec)
[docs] def rotate(self, angle, axis, origin): """Rotate this object by a certain angle around an axis and origin. Args: angle: An angle for rotation in degrees. axis: Rotation axis as a Vector3D. origin: A ladybug_geometry Point3D for the origin around which the object will be rotated. """ if self.space_polygon_geometry is not None: self._space_polygon_geometry = \ self.space_polygon_geometry.rotate(math.radians(angle), axis, origin)
[docs] def rotate_xy(self, angle, origin): """Rotate this object counterclockwise in the world XY plane by a certain angle. Args: angle: An angle in degrees. origin: A ladybug_geometry Point3D for the origin around which the object will be rotated. """ if self.space_polygon_geometry is not None: self._space_polygon_geometry = \ self.space_polygon_geometry.rotate_xy(math.radians(angle), origin)
[docs] def reflect(self, plane): """Reflect this object across a plane. Args: plane: A ladybug_geometry Plane across which the object will be reflected. """ if self.space_polygon_geometry is not None: self._space_polygon_geometry = self.space_polygon_geometry.reflect(plane)
[docs] def scale(self, factor, origin=None): """Scale this object by a factor from an origin point. Args: factor: A number representing how much the object should be scaled. origin: A ladybug_geometry Point3D representing the origin from which to scale. If None, it will be scaled from the World origin (0, 0, 0). """ if self.space_polygon_geometry is not None: self._space_polygon_geometry = \ self.space_polygon_geometry.scale(factor, origin)
[docs] @classmethod def from_dict(cls, data, host): """Create RoomDoe2Properties from a dictionary. Args: data: A dictionary representation of RoomDoe2Properties with the format below. host: A Room object that hosts these properties. .. code-block:: python { "type": 'RoomDoe2Properties', "assigned_flow": 100, # number in cfm "flow_per_area": 1, # number in cfm/ft2 "min_flow_ratio": 0.3, # number between 0 and 1 "min_flow_per_area": 0.3, # number in cfm/ft2 "hmax_flow_ratio": 0.3, # number between 0 and 1 "space_polygon_geometry": {} # optional Face3D dictionary } """ assert data['type'] == 'RoomDoe2Properties', \ 'Expected RoomDoe2Properties. Got {}.'.format(data['type']) new_prop = cls(host) auto_dict = autocalculate.to_dict() if 'assigned_flow' in data and data['assigned_flow'] != auto_dict: new_prop.assigned_flow = data['assigned_flow'] if 'flow_per_area' in data and data['flow_per_area'] != auto_dict: new_prop.flow_per_area = data['flow_per_area'] if 'min_flow_ratio' in data and data['min_flow_ratio'] != auto_dict: new_prop.min_flow_ratio = data['min_flow_ratio'] if 'min_flow_per_area' in data and data['min_flow_per_area'] != auto_dict: new_prop.min_flow_per_area = data['min_flow_per_area'] if 'hmax_flow_ratio' in data and data['hmax_flow_ratio'] != auto_dict: new_prop.hmax_flow_ratio = data['hmax_flow_ratio'] if 'space_polygon_geometry' in data and \ data['space_polygon_geometry'] is not None: new_prop.space_polygon_geometry = \ Face3D.from_dict(data['space_polygon_geometry']) return new_prop
[docs] def apply_properties_from_dict(self, data): """Apply properties from a RoomDoe2Properties dictionary. Args: data: A RoomDoe2Properties dictionary (typically coming from a Model). """ auto_dict = autocalculate.to_dict() if 'assigned_flow' in data and data['assigned_flow'] != auto_dict: self.assigned_flow = data['assigned_flow'] if 'flow_per_area' in data and data['flow_per_area'] != auto_dict: self.flow_per_area = data['flow_per_area'] if 'min_flow_ratio' in data and data['min_flow_ratio'] != auto_dict: self.min_flow_ratio = data['min_flow_ratio'] if 'min_flow_per_area' in data and data['min_flow_per_area'] != auto_dict: self.min_flow_per_area = data['min_flow_per_area'] if 'hmax_flow_ratio' in data and data['hmax_flow_ratio'] != auto_dict: self.hmax_flow_ratio = data['hmax_flow_ratio'] if 'space_polygon_geometry' in data and \ data['space_polygon_geometry'] is not None: self.space_polygon_geometry = \ Face3D.from_dict(data['space_polygon_geometry'])
[docs] def apply_properties_from_user_data(self): """Apply properties from a the user_data assigned to the host room. For this method to successfully assign properties from user_data, the properties on this object must currently be None and the keys in user_data must use the INP convention for each of the attributes, which must be CAPITALIZED like the following: .. code-block:: python { "ASSIGNED-FLOW": 100, # number in cfm "FLOW/AREA": 1, # number in cfm/ft2 "MIN-FLOW-RATIO": 0.3, # number between 0 and 1 "MIN-FLOW/AREA": 0.3, # number in cfm/ft2 "HMAX-FLOW-RATIO": 0.3 # number between 0 and 1 } """ attrs = ('assigned_flow', 'flow_per_area', 'min_flow_ratio', 'min_flow_per_area', 'hmax_flow_ratio') data = self.host.user_data if data is not None: for key, attr in zip(MECH_AIRFLOW_KEYS, attrs): if key in data and getattr(self, attr) is None: try: setattr(self, attr, data[key]) except Exception: pass # it's user_data; users are allowed to make mistakes
[docs] def to_dict(self, abridged=False): """Return Room Doe2 properties as a dictionary.""" base = {'doe2': {}} base['doe2']['type'] = 'RoomDoe2Properties' if self.assigned_flow is not None: base['doe2']['assigned_flow'] = self.assigned_flow if self.flow_per_area is not None: base['doe2']['flow_per_area'] = self.flow_per_area if self.min_flow_ratio is not None: base['doe2']['min_flow_ratio'] = self.min_flow_ratio if self.min_flow_per_area is not None: base['doe2']['min_flow_per_area'] = self.min_flow_per_area if self.hmax_flow_ratio is not None: base['doe2']['hmax_flow_ratio'] = self.hmax_flow_ratio if self.space_polygon_geometry is not None: base['doe2']['space_polygon_geometry'] = \ self.space_polygon_geometry.to_dict() return base
[docs] def to_inp(self): """Get RoomDoe2Properties as INP (Keywords, Values). Returns: A tuple with two elements. - keywords: A list of text strings for keywords to assign to the room. - values: A list of text strings that aligns with the keywords and denotes the value for each keyword. """ keywords = [] values = [] attrs = ('assigned_flow', 'flow_per_area', 'min_flow_ratio', 'min_flow_per_area', 'hmax_flow_ratio') for key, attr in zip(MECH_AIRFLOW_KEYS, attrs): attr_value = getattr(self, attr) if attr_value is not None: keywords.append(key) values.append(attr_value) return keywords, values
[docs] def duplicate(self, new_host=None): """Get a copy of this object. Args: new_host: A new Room object that hosts these properties. If None, the properties will be duplicated with the same host. """ _host = new_host or self._host new_room = RoomDoe2Properties( _host, self.assigned_flow, self.flow_per_area, self.min_flow_ratio, self.min_flow_per_area, self.hmax_flow_ratio, self.space_polygon_geometry) return new_room
[docs] def ToString(self): return self.__repr__()
def __repr__(self): return 'Room DOE2 Properties: [host: {}]'.format(self.host.display_name)