Source code for honeybee_energy.hvac.detailed

# coding=utf-8
"""Detailed HVAC system object defined using IronBug or OpenStudio .NET bindings."""
from __future__ import division

from honeybee._lockable import lockable

from ._base import _HVACSystem


[docs] @lockable class DetailedHVAC(_HVACSystem): """Detailed HVAC system object defined using IronBug or OpenStudio .NET bindings. Args: identifier: Text string for detailed system identifier. Must be < 100 characters and not contain any EnergyPlus special characters. specification: A JSON-serializable dictionary representing the full specification of the detailed system. This can be obtained by calling the ToJson() method on any IronBug HVAC system and then serializing the resulting JSON string into a Python dictionary using the native Python json package. Note that the Rooms that the HVAC is assigned to must be specified as ThermalZones under this specification in order for the resulting Model this HVAC is a part of to be valid. Properties: * identifier * specification * air_loop_count * thermal_zones * display_name * user_data """ __slots__ = ('_specification', '_air_loop_count', '_thermal_zones') def __init__(self, identifier, specification): """Initialize DetailedHVAC.""" # initialize base HVAC system properties _HVACSystem.__init__(self, identifier) self.specification = specification @property def specification(self): """Get or set a dictionary for the full specification of this HVAC. This can be obtained by calling the SaveAsJson() method on any IronBug HVAC system and then serializing the resulting JSON string into a Python dictionary using the native Python json package. """ return self._specification @specification.setter def specification(self, value): assert isinstance(value, dict), 'Expected dictionary for DetailedHVAC' \ 'object specification. Got {}.'.format(type(value)) thermal_zones, air_loop_count = [], 0 try: for a_loop in value['AirLoops']: if a_loop['$type'].startswith('Ironbug.HVAC.IB_NoAirLoop'): for zone in a_loop['ThermalZones']: for z_attr in zone['CustomAttributes']: if z_attr['Field']['FullName'] == 'Name': thermal_zones.append(z_attr['Value']) elif a_loop['$type'].startswith('Ironbug.HVAC.IB_AirLoopHVAC'): air_loop_count += 1 for comp in a_loop['DemandComponents']: if comp['$type'].startswith('Ironbug.HVAC.IB_AirLoopBranches'): for branch in comp['Branches']: for z_attr in branch[0]['CustomAttributes']: if z_attr['Field']['FullName'] == 'Name': thermal_zones.append(z_attr['Value']) else: raise ValueError('DetailedHVAC specification does not contain ' 'any ThermalZones that can be matched to Rooms.') except KeyError as e: raise ValueError('DetailedHVAC specification is not valid:\n{}'.format(e)) self._air_loop_count = air_loop_count self._thermal_zones = tuple(thermal_zones) self._specification = value @property def air_loop_count(self): """Get an integer for the number of air loops in the system.""" return self._air_loop_count @property def thermal_zones(self): """Get a tuple of strings for the Rooms/Zones to which the HVAC is assigned.""" return self._thermal_zones
[docs] def sync_room_ids(self, room_map): """Sync this DetailedHVAC with Rooms that had their IDs changed. This is useful after running the Model.reset_ids() command to ensure that the bi-directional Room references between DetailedHVAC and Honeybee Rooms is correct. Args: room_map: A dictionary that relates the original Rooms identifiers (keys) to the new identifiers (values) of the Rooms in the Model. """ thermal_zones, air_loop_count = [], 0 hvac_spec = self._specification for a_loop in hvac_spec['AirLoops']: if a_loop['$type'].startswith('Ironbug.HVAC.IB_NoAirLoop'): for zone in a_loop['ThermalZones']: for z_attr in zone['CustomAttributes']: if z_attr['Field']['FullName'] == 'Name': z_attr['Value'] = room_map[z_attr['Value']] thermal_zones.append(z_attr['Value']) elif a_loop['$type'].startswith('Ironbug.HVAC.IB_AirLoopHVAC'): air_loop_count += 1 for comp in a_loop['DemandComponents']: if comp['$type'].startswith('Ironbug.HVAC.IB_AirLoopBranches'): for branch in comp['Branches']: for z_attr in branch[0]['CustomAttributes']: if z_attr['Field']['FullName'] == 'Name': z_attr['Value'] = room_map[z_attr['Value']] thermal_zones.append(z_attr['Value']) # unlock object and set attributes was_locked = False if self._locked: was_locked = True self.unlock() self._air_loop_count = air_loop_count self._thermal_zones = tuple(thermal_zones) self._specification = hvac_spec if was_locked: # set the object back to being locked self.lock()
[docs] def to_ideal_air_equivalent(self): """This method is NOT YET IMPLEMENTED.""" # TODO: Consider supporting this method by analyzing the air loop # sensing economizers, DCV, and heat recovery seems doable # but sensing heating-only and cooling-only systems seems more challenging msg = 'DetailedHVAC "{}" cannot be translated to an ideal air ' \ 'equivalent.'.format(self.display_name) raise NotImplementedError(msg)
[docs] @classmethod def from_dict(cls, data): """Create a HVAC object from a dictionary. Args: data: A HVAC dictionary in following the format below. .. code-block:: python { "type": "DetailedHVAC", "identifier": "Classroom1_System", # identifier for the HVAC "display_name": "Custom VAV System", # name for the HVAC "specification": {} # dictionary for the full HVAC specification } """ assert data['type'] == 'DetailedHVAC', \ 'Expected {} dictionary. Got {}.'.format('DetailedHVAC', data['type']) new_obj = cls(data['identifier'], data['specification']) 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, schedule_dict): """Create a HVAC object from an abridged dictionary. Args: data: An abridged dictionary in following the format below. schedule_dict: A dictionary with schedule identifiers as keys and honeybee schedule objects as values. .. code-block:: python { "type": "DetailedHVAC", "identifier": "Classroom1_System", # identifier for the HVAC "display_name": "Custom VAV System", # name for the HVAC "specification": {} # dictionary for the full HVAC specification } """ # this is the same as the from_dict method for as long as there are not schedules return cls.from_dict(data)
[docs] def to_dict(self, abridged=False): """DetailedHVAC dictionary representation. Args: abridged: Boolean to note whether the full dictionary describing the object should be returned (False) or just an abridged version (True). This input currently has no effect but may eventually have one if schedule-type properties are exposed on this object. """ base = {'type': 'DetailedHVAC'} base['identifier'] = self.identifier base['specification'] = self.specification 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
def __copy__(self): new_obj = self.__class__(self.identifier, self.specification.copy()) 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, self._air_loop_count) + self._thermal_zones def __hash__(self): return hash(self.__key()) def __eq__(self, other): return isinstance(other, self.__class__) and self.__key() == other.__key() def __ne__(self, other): return not self.__eq__(other) def __repr__(self): return 'DetailedHVAC: {} [air loops: {}] [zones: {}]'.format( self.display_name, self.air_loop_count, len(self.thermal_zones))