# -*- coding: utf-8 -*-
# -*- Python Version: 2.7 -*-
"""HB-Room Passive-House-HVAC-Equipment Properties."""
try:
from typing import Any, Dict, Optional, Set
except ImportError:
pass # Python2.7
try:
from ladybug_geometry.geometry3d.plane import Plane
from ladybug_geometry.geometry3d.pointvector import Point3D
except ImportError as e:
raise ImportError("\nFailed to import ladybug_geometry:\n\t{}".format(e))
try:
from honeybee import room
from honeybee.properties import RoomProperties
except ImportError as e:
raise ImportError("\nFailed to import honeybee:\n\t{}".format(e))
try:
from honeybee_ph import space
except ImportError as e:
raise ImportError("\nFailed to import honeybee_ph:\n\t{}".format(e))
try:
from honeybee_phhvac.heat_pumps import PhHeatPumpSystem, PhHeatPumpSystemBuilder
from honeybee_phhvac.heating import PhHeatingSystem, PhHeatingSystemBuilder
from honeybee_phhvac.hot_water_system import PhHotWaterSystem
from honeybee_phhvac.renewable_devices import PhRenewableEnergyDevice, PhRenewableEnergyDeviceBuilder
from honeybee_phhvac.supportive_device import PhSupportiveDevice
from honeybee_phhvac.ventilation import PhExhaustDeviceBuilder, PhVentilationSystem, _ExhaustVentilatorBase
except ImportError as e:
raise ImportError("\nFailed to import honeybee_phhvac:\n\t{}".format(e))
[docs]
class RoomPhHvacProperties_FromDictError(Exception):
def __init__(self, _expected_types, _input_type):
self.msg = 'Error: Expected type of "{}". Got: {}'.format(_expected_types, _input_type)
super(RoomPhHvacProperties_FromDictError, self).__init__(self.msg)
[docs]
class RoomPhHvacProperties(object):
def __init__(self, _host):
# type: (Optional[RoomProperties]) -> None
self._host = _host
self.id_num = 0
self._ventilation_system = None # type: Optional[PhVentilationSystem]
self._heating_systems = set() # type: set[PhHeatingSystem]
self._heat_pump_systems = set() # type: set[PhHeatPumpSystem]
self._exhaust_vent_devices = set() # type: set[_ExhaustVentilatorBase]
self._supportive_devices = set() # type: set[PhSupportiveDevice]
self._renewable_devices = set() # type: set[PhRenewableEnergyDevice]
self._hot_water_system = None # type: Optional[PhHotWaterSystem]
@property
def host(self):
# type: () -> Optional[RoomProperties]
return self._host
@property
def ventilation_system(self):
# type: () -> Optional[PhVentilationSystem]
return self._ventilation_system
@property
def heating_systems(self):
# type: () -> Set[PhHeatingSystem]
return self._heating_systems
@property
def heat_pump_systems(self):
# type: () -> Set[PhHeatPumpSystem]
return self._heat_pump_systems
@property
def exhaust_vent_devices(self):
# type: () -> Set[_ExhaustVentilatorBase]
return self._exhaust_vent_devices
@property
def supportive_devices(self):
# type: () -> Set[PhSupportiveDevice]
return self._supportive_devices
@property
def renewable_devices(self):
# type: () -> Set[PhRenewableEnergyDevice]
return self._renewable_devices
@property
def hot_water_system(self):
# type: () -> Optional[PhHotWaterSystem]
return self._hot_water_system
[docs]
def set_ventilation_system(self, _ventilation_system):
# type: (Optional[PhVentilationSystem]) -> None
"""Set the Ventilation System serving the Room."""
self._ventilation_system = _ventilation_system
[docs]
def add_heating_system(self, _heating_system):
# type: (Optional[PhHeatingSystem]) -> None
"""Add a Heating System serving the Room."""
if _heating_system:
self._heating_systems.add(_heating_system)
[docs]
def add_heat_pump_system(self, _heat_pump_system):
# type: (Optional[PhHeatPumpSystem]) -> None
"""Add a Heat Pump System serving the Room."""
if _heat_pump_system:
self._heat_pump_systems.add(_heat_pump_system)
[docs]
def add_exhaust_vent_device(self, _exhaust_vent_device):
# type: (Optional[_ExhaustVentilatorBase]) -> None
"""Add an Exhaust Vent Device serving the Room."""
if _exhaust_vent_device:
self._exhaust_vent_devices.add(_exhaust_vent_device)
[docs]
def add_supportive_device(self, _supportive_device):
# type: (Optional[PhSupportiveDevice]) -> None
"""Add a Supportive Device serving the Room."""
if _supportive_device:
self._supportive_devices.add(_supportive_device)
[docs]
def add_renewable_device(self, _renewable_device):
# type: (Optional[PhRenewableEnergyDevice]) -> None
"""Add a Renewable Energy Device serving the Room."""
if _renewable_device:
self._renewable_devices.add(_renewable_device)
[docs]
def set_hot_water_system(self, _hot_water_system):
# type: (Optional[PhHotWaterSystem]) -> None
"""Set the Hot Water System serving the Room."""
self._hot_water_system = _hot_water_system
[docs]
def clear_systems(self):
"""Clear all the HVAC Systems from the Room."""
self._ventilation_system = None
self._heating_systems.clear()
self._heat_pump_systems.clear()
self._exhaust_vent_devices.clear()
self._supportive_devices.clear()
self._renewable_devices.clear()
self._hot_water_system = None
[docs]
def to_dict(self, abridged=False):
# type: (bool) -> Dict[str, Any]
d = {}
if abridged:
d["type"] = "RoomPhHvacPropertiesAbridged"
else:
d["type"] = "RoomPhHvacProperties"
d["id_num"] = self.id_num
d["ventilation_system"] = self.ventilation_system.to_dict() if self.ventilation_system else None
d["heating_systems"] = [sys.to_dict() for sys in sorted([_ for _ in self.heating_systems if _ is not None])]
d["heat_pump_systems"] = [sys.to_dict() for sys in sorted([_ for _ in self.heat_pump_systems if _ is not None])]
d["exhaust_vent_devices"] = [
sys.to_dict() for sys in sorted([_ for _ in self.exhaust_vent_devices if _ is not None])
]
d["supportive_devices"] = [
device.to_dict() for device in sorted([_ for _ in self.supportive_devices if _ is not None])
]
d["renewable_devices"] = [
device.to_dict() for device in sorted([_ for _ in self.renewable_devices if _ is not None])
]
d["hot_water_system"] = self.hot_water_system.to_dict() if self.hot_water_system else None
return {"ph_hvac": d}
[docs]
@classmethod
def from_dict(cls, _input_dict, host):
# type: (Dict[str, Any], Optional[RoomProperties]) -> RoomPhHvacProperties
valid_types = ("RoomPhHvacProperties", "RoomPhHvacPropertiesAbridged")
if _input_dict["type"] not in valid_types:
raise RoomPhHvacProperties_FromDictError(valid_types, _input_dict["type"])
new_prop = cls(host)
new_prop.id_num = _input_dict.get("id_num", 0)
vent_sys_dict = _input_dict.get("ventilation_system")
if vent_sys_dict:
new_prop.set_ventilation_system(PhVentilationSystem.from_dict(vent_sys_dict))
for htg_sys_dict in _input_dict.get("heating_systems", []):
htg_sys = PhHeatingSystemBuilder.from_dict(htg_sys_dict)
new_prop.add_heating_system(htg_sys)
for heat_pump_sys_dict in _input_dict.get("heat_pump_systems", []):
heat_pump_sys = PhHeatPumpSystemBuilder.from_dict(heat_pump_sys_dict)
new_prop.add_heat_pump_system(heat_pump_sys)
for exhaust_vent_device_dict in _input_dict.get("exhaust_vent_devices", []):
exhaust_device = PhExhaustDeviceBuilder.from_dict(exhaust_vent_device_dict)
new_prop.add_exhaust_vent_device(exhaust_device)
for supportive_device_dict in _input_dict.get("supportive_devices", []):
supportive_device = PhSupportiveDevice.from_dict(supportive_device_dict)
new_prop.add_supportive_device(supportive_device)
for renewable_device_dict in _input_dict.get("renewable_devices", []):
renewable_device = PhRenewableEnergyDeviceBuilder.from_dict(renewable_device_dict)
new_prop.add_renewable_device(renewable_device)
hot_water_sys_dict = _input_dict.get("hot_water_system")
if hot_water_sys_dict:
new_prop.set_hot_water_system(PhHotWaterSystem.from_dict(hot_water_sys_dict))
return new_prop
[docs]
def apply_properties_from_dict(self, room_prop_dict, mech_systems, *args, **kwargs):
# type: (Dict[str, Any], Dict[str, dict[str, Any]], list, dict) -> None
"""Apply properties from a RoomPhHvacPropertiesAbridged dictionary."""
self.id_num = room_prop_dict["id_num"]
# -- Find the identifiers for each of the room's mechanical systems
vent_sys_dict = room_prop_dict.get("ventilation_system", {}) or {}
vent_system_id = vent_sys_dict.get("identifier", None)
heating_system_ids = [sys.get("identifier") for sys in room_prop_dict.get("heating_systems", [])]
heat_pump_system_ids = [sys.get("identifier") for sys in room_prop_dict.get("heat_pump_systems", [])]
exhaust_vent_ids = [sys.get("identifier") for sys in room_prop_dict.get("exhaust_vent_devices", [])]
supportive_device_ids = [sys.get("identifier") for sys in room_prop_dict.get("supportive_devices", [])]
renewable_device_ids = [sys.get("identifier") for sys in room_prop_dict.get("renewable_devices", [])]
hot_water_sys_dict = room_prop_dict.get("hot_water_system", {}) or {}
hot_water_sys_id = hot_water_sys_dict.get("identifier", None)
# -- Pull out the actual mechanical systems from the dictionary and apply them to the Properties
self.set_ventilation_system(mech_systems.get("ventilation_systems", {}).get(vent_system_id, None))
for sys in (mech_systems.get("heating_systems", {}).get(_id) for _id in heating_system_ids):
self.add_heating_system(sys)
for sys in (mech_systems.get("heat_pump_systems", {}).get(_id) for _id in heat_pump_system_ids):
self.add_heat_pump_system(sys)
for sys in (mech_systems.get("exhaust_vent_devices", {}).get(_id) for _id in exhaust_vent_ids):
self.add_exhaust_vent_device(sys)
for sys in (mech_systems.get("supportive_devices", {}).get(_id) for _id in supportive_device_ids):
self.add_supportive_device(sys)
for sys in (mech_systems.get("renewable_devices", {}).get(_id) for _id in renewable_device_ids):
self.add_renewable_device(sys)
self.set_hot_water_system(mech_systems.get("hot_water_systems", {}).get(hot_water_sys_id, None))
return None
def __copy__(self, new_host=None, *args, **kwargs):
# type: (Optional[RoomProperties], list, dict) -> RoomPhHvacProperties
return self.duplicate(new_host)
[docs]
def duplicate(self, new_host=None, *args, **kwargs):
# type: (Optional[RoomProperties], list, dict) -> RoomPhHvacProperties
_host = new_host or self._host
new_obj = RoomPhHvacProperties(_host)
new_obj.id_num = self.id_num
new_obj.set_ventilation_system(self.ventilation_system.duplicate() if self.ventilation_system else None)
for htg_sys in self.heating_systems:
new_obj.add_heating_system(htg_sys.duplicate())
for heat_pump_sys in self.heat_pump_systems:
new_obj.add_heat_pump_system(heat_pump_sys.duplicate())
for exhaust_device in self.exhaust_vent_devices:
new_obj.add_exhaust_vent_device(exhaust_device.duplicate())
for supportive_device in self.supportive_devices:
new_obj.add_supportive_device(supportive_device.duplicate())
for renewable_device in self.renewable_devices:
new_obj.add_renewable_device(renewable_device.duplicate())
new_obj.set_hot_water_system(self.hot_water_system.duplicate() if self.hot_water_system else None)
return new_obj
[docs]
def move(self, move_vec3D):
"""Move the Room's HVAC Systems along a vector.
When used in within Honeybee, this method will most often be triggered as part of a
larger model-transform. For instance, when triggered during a Room's
`honeybee.properties._Properties` transform.
When this method is used on its own, it is best practice to duplicate the
object before applying this transform since it applies the transform to the object
directly, rather than returning a new object with the transform applied.
Args:
move_vec3D: A Vector3D with the direction and distance to move the ray.
"""
if self._ventilation_system:
self.set_ventilation_system(self._ventilation_system.move(move_vec3D))
# Not Implemented
# for sys in self._heating_systems:
# sys.move(move_vec3D)
# for sys in self._heat_pump_systems:
# sys.move(move_vec3D)
# for sys in self._exhaust_vent_devices:
# sys.move(move_vec3D)
# for sys in self._supportive_devices:
# sys.move(move_vec3D)
# for sys in self._renewable_devices:
# sys.move(move_vec3D)
if self._hot_water_system:
self.set_hot_water_system(self._hot_water_system.move(move_vec3D))
[docs]
def rotate(self, axis_vec3D, angle_degrees, origin_pt3D):
"""Rotate the Room's HVAC Systems by a certain angle around an axis and origin.
When used in within Honeybee, this method will most often be triggered as part of a
larger model-transform. For instance, when triggered during a Room's
`honeybee.properties._Properties` transform.
When this method is used on its own, it is best practice to duplicate the
object before applying this transform since it applies the transform to the object
directly, rather than returning a new object with the transform applied.
Right hand rule applies:
If axis has a positive orientation, rotation will be clockwise.
If axis has a negative orientation, rotation will be counterclockwise.
Args:
axis_vec3D: A Vector3D axis representing the axis of rotation.
angle_degrees: An angle for rotation in degrees.
origin_pt3D: A Point3D for the origin around which the object will be rotated.
"""
if self._ventilation_system:
self.set_ventilation_system(self._ventilation_system.rotate(axis_vec3D, angle_degrees, origin_pt3D))
# Not Implemented
# for sys in self._heating_systems:
# sys.rotate(axis_vec3D, angle_degrees, origin_pt3D)
# for sys in self._heat_pump_systems:
# sys.rotate(axis_vec3D, angle_degrees, origin_pt3D)
# for sys in self._exhaust_vent_devices:
# sys.rotate(axis_vec3D, angle_degrees, origin_pt3D)
# for sys in self._supportive_devices:
# sys.rotate(axis_vec3D, angle_degrees, origin_pt3D)
# for sys in self._renewable_devices:
# sys.rotate(axis_vec3D, angle_degrees, origin_pt3D)
if self._hot_water_system:
self.set_hot_water_system(self._hot_water_system.rotate(axis_vec3D, angle_degrees, origin_pt3D))
[docs]
def rotate_xy(self, angle_degree, origin_pt3D):
# type: (float, Point3D) -> None
"""Rotate the Room's HVAC Systems counterclockwise in the XY plane by a certain angle.
When used in within Honeybee, this method will most often be triggered as part of a
larger model-transform. For instance, when triggered during a Room's
`honeybee.properties._Properties` transform.
When this method is used on its own, it is best practice to duplicate the
object before applying this transform since it applies the transform to the object
directly, rather than returning a new object with the transform applied.
Args:
angle_degree: An angle in degrees.
origin_pt3D: A Point3D for the origin around which the object will be rotated.
"""
if self._ventilation_system:
self.set_ventilation_system(self._ventilation_system.rotate_xy(angle_degree, origin_pt3D))
# Not Implemented
# for sys in self._heating_systems:
# sys.rotate_xy(angle_degree, origin_pt3D)
# for sys in self._heat_pump_systems:
# sys.rotate_xy(angle_degree, origin_pt3D)
# for sys in self._exhaust_vent_devices:
# sys.rotate_xy(angle_degree, origin_pt3D)
# for sys in self._supportive_devices:
# sys.rotate_xy(angle_degree, origin_pt3D)
# for sys in self._renewable_devices:
# sys.rotate_xy(angle_degree, origin_pt3D)
if self._hot_water_system:
self.set_hot_water_system(self._hot_water_system.rotate_xy(angle_degree, origin_pt3D))
[docs]
def reflect(self, plane):
# type: (Plane) -> None
"""Reflected the Room's HVAC Systems across a plane with the input normal vector and origin.
When used in within Honeybee, this method will most often be triggered as part of a
larger model-transform. For instance, when triggered during a Room's
`honeybee.properties._Properties` transform.
When this method is used on its own, it is best practice to duplicate the
object before applying this transform since it applies the transform to the object
directly, rather than returning a new object with the transform applied.
Args:
plane: A Plane object representing the plane across which the object will be reflected.
"""
if self._ventilation_system:
self.set_ventilation_system(self._ventilation_system.reflect(plane.n, plane.o))
# Not Implemented
# for sys in self._heating_systems:
# sys.reflect(plane.n, plane.o)
# for sys in self._heat_pump_systems:
# sys.reflect(plane.n, plane.o)
# for sys in self._exhaust_vent_devices:
# sys.reflect(plane.n, plane.o)
# for sys in self._supportive_devices:
# sys.reflect(plane.n, plane.o)
# for sys in self._renewable_devices:
# sys.reflect(plane.n, plane.o)
if self._hot_water_system:
self.set_hot_water_system(self._hot_water_system.reflect(plane.n, plane.o))
[docs]
def scale(self, scale_factor, origin_pt3D=None):
"""Scale the Room's HVAC Systems by a factor from an origin point.
When used in within Honeybee, this method will most often be triggered as part of a
larger model-transform. For instance, when triggered during a Room's
`honeybee.properties._Properties` transform.
When this method is used on its own, it is best practice to duplicate the
object before applying this transform since it applies the transform to the object
directly, rather than returning a new object with the transform applied.
Args:
scale_factor: A number representing how much the line segment should be scaled.
origin_pt3D: A Point3D representing the origin from which to scale.
If None, it will be scaled from the World origin (0, 0, 0).
"""
if self._ventilation_system:
self.set_ventilation_system(self._ventilation_system.scale(scale_factor, origin_pt3D))
# Not Implemented
# for sys in self._heating_systems:
# sys.scale(scale_factor, origin_pt3D)
# for sys in self._heat_pump_systems:
# sys.scale(scale_factor, origin_pt3D)
# for sys in self._exhaust_vent_devices:
# sys.scale(scale_factor, origin_pt3D)
# for sys in self._supportive_devices:
# sys.scale(scale_factor, origin_pt3D)
# for sys in self._renewable_devices:
# sys.scale(scale_factor, origin_pt3D)
if self._hot_water_system:
self.set_hot_water_system(self._hot_water_system.scale(scale_factor, origin_pt3D))
def __str__(self):
# type: () -> str
return "{}(host={!r})".format(self.__class__.__name__, self.host)
def __repr__(self):
# type: () -> str
return str(self)
[docs]
def ToString(self):
# type: () -> str
return self.__repr__()
# -----------------------------------------------------------------------------
# -- Helper Functions to get HVAC Devices and Properties from HB-Room and HB-Space
[docs]
def get_ph_hvac_prop_from_room(_room):
# type: (room.Room) -> RoomPhHvacProperties
"""Get the RoomPhHvacProperties of a HB-Room object."""
return getattr(_room.properties, "ph_hvac")
[docs]
def get_ph_hvac_from_space(_space):
# type: (space.Space) -> Optional[RoomPhHvacProperties]
"""Return the "ph_hvac" Properties of a Honeybee-PH Space's host Room."""
if not _space.host:
return None
return getattr(_space.host.properties, "ph_hvac")
[docs]
def get_ventilation_system_from_space(_space):
# type: (space.Space) -> Optional[PhVentilationSystem]
"""Get the Ventilation System from a Honeybee-PH Space."""
ph_hvac = get_ph_hvac_from_space(_space)
if not ph_hvac:
return None
return ph_hvac.ventilation_system
[docs]
def get_exhaust_vent_devices_from_space(_hph_space):
# type: (space.Space) -> Set[_ExhaustVentilatorBase]
"""Return a set of all the ExhaustVentilators found on a space's host HB Room."""
hvac_prop_ph = get_ph_hvac_from_space(_hph_space)
if not hvac_prop_ph:
return set()
return hvac_prop_ph.exhaust_vent_devices
[docs]
def get_heating_systems_from_space(_space):
# type: (space.Space)-> Set[PhHeatingSystem]
"""Return the Heating Systems from a Honeybee-PH Space."""
ph_hvac = get_ph_hvac_from_space(_space)
if not ph_hvac:
return set()
return ph_hvac.heating_systems
[docs]
def get_heat_pump_systems_from_space(_space):
# type: (space.Space) -> Set[PhHeatPumpSystem]
"""Return the Heat-Pump Systems from a Honeybee-PH Space."""
ph_hvac = get_ph_hvac_from_space(_space)
if not ph_hvac:
return set()
return ph_hvac.heat_pump_systems
[docs]
def get_supportive_devices_from_space(_hph_space):
# type: ( space.Space) -> Set[PhSupportiveDevice]
"""Return a set of all the SupportiveDevices found on a space's host HB Room."""
hvac_prop_ph = get_ph_hvac_from_space(_hph_space)
if not hvac_prop_ph:
return set()
else:
return hvac_prop_ph.supportive_devices
[docs]
def get_renewable_devices_from_space(_hph_space):
# type: (space.Space) -> Set[PhRenewableEnergyDevice]
"""Return a set of all the Renewable Energy Devices found on a space's host HB Room."""
hvac_prop_ph = get_ph_hvac_from_space(_hph_space)
if not hvac_prop_ph:
return set()
else:
return hvac_prop_ph.renewable_devices
[docs]
def get_hot_water_system_from_space(_space):
# type: (space.Space) -> Optional[PhHotWaterSystem]
"""Get the Hot Water System from a Honeybee-PH Space."""
ph_hvac = get_ph_hvac_from_space(_space)
if not ph_hvac:
return None
return ph_hvac.hot_water_system