Skip to content

Commit

Permalink
feat(thermal_bridges): TB into WUFI-Passive
Browse files Browse the repository at this point in the history
Support Thermal Bridge entry in WUFI-Passive
  • Loading branch information
ed-p-may authored Jan 13, 2023
2 parents 6daca02 + 2442642 commit 01801f6
Show file tree
Hide file tree
Showing 15 changed files with 631 additions and 547 deletions.
13 changes: 7 additions & 6 deletions PHX/PHPP/phpp_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,13 +373,14 @@ def write_project_thermal_bridges(self, phx_project: project.PhxProject) -> None

thermal_bridges: List[areas_thermal_bridges.ThermalBridgeRow] = []
for variant in phx_project.variants:
for phx_tb in variant.building.thermal_bridges:
thermal_bridges.append(
areas_thermal_bridges.ThermalBridgeRow(
self.shape.AREAS,
phx_tb
for zone in variant.zones:
for phx_tb in zone.thermal_bridges:
thermal_bridges.append(
areas_thermal_bridges.ThermalBridgeRow(
self.shape.AREAS,
phx_tb
)
)
)

if len(thermal_bridges) >= 100:
print(f"Warning: {len(thermal_bridges)} thermal bridges found in the model. Ensure that you have "
Expand Down
26 changes: 15 additions & 11 deletions PHX/from_HBJSON/create_building.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
from typing import List, Union, Dict

from honeybee import room, aperture, face
from honeybee_ph import space
from honeybee_energy.properties.room import RoomEnergyProperties
from honeybee_energy_ph.properties.load.people import PeoplePhProperties

from PHX.model import building, constructions, components
from PHX.from_HBJSON import create_rooms, create_geometry
Expand Down Expand Up @@ -260,10 +263,9 @@ def create_zones_from_hb_room(_hb_room: room.Room) -> building.PhxZone:
new_zone.id_num = building.PhxZone._count
new_zone.display_name = _hb_room.display_name

# -- Sort the room order by full_name
sorted_spaces = sorted(
_hb_room.properties.ph.spaces, key=lambda space: space.full_name
)
# -- Sort the HB-Room's Spaces by their full_name
spaces: List[space.Space] = _hb_room.properties.ph.spaces # type: ignore
sorted_spaces = sorted(spaces, key=lambda space: space.full_name)

# -- Create a new WUFI-RoomVentilation for each space
new_zone.wufi_rooms = [
Expand All @@ -277,13 +279,15 @@ def create_zones_from_hb_room(_hb_room: room.Room) -> building.PhxZone:
)
new_zone.volume_net = sum((rm.net_volume for rm in new_zone.wufi_rooms))

# Set the zone's occupancy based on the merged HB room
new_zone.res_occupant_quantity = (
_hb_room.properties.energy.people.properties.ph.number_people
)
new_zone.res_number_bedrooms = (
_hb_room.properties.energy.people.properties.ph.number_bedrooms
)
# -- Set the zone's occupancy based on the merged HB room
room_energy_prop: RoomEnergyProperties = _hb_room.properties.energy # type: ignore
hbph_people_prop: PeoplePhProperties = room_energy_prop.people.properties.ph # type: ignore
new_zone.res_occupant_quantity = hbph_people_prop.number_people
new_zone.res_number_bedrooms = hbph_people_prop.number_bedrooms

# -- Set the Zones' thermal bridges
for phx_thermal_bridge in create_thermal_bridges_from_hb_room(_hb_room):
new_zone.add_thermal_bridges(phx_thermal_bridge)

return new_zone

Expand Down
3 changes: 0 additions & 3 deletions PHX/from_HBJSON/create_variant.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,6 @@ def add_building_from_hb_room(
)
)
_variant.building.add_zones(create_building.create_zones_from_hb_room(_hb_room))
_variant.building.add_thermal_bridges(
create_building.create_thermal_bridges_from_hb_room(_hb_room)
)

if group_components:
_variant.building.merge_opaque_components_by_assembly()
Expand Down
47 changes: 22 additions & 25 deletions PHX/model/building.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
PhxComponentThermalBridge,
)
from PHX.model.hvac import collection
from PHX.model.enums.building import ComponentFaceOpacity


@dataclass
Expand All @@ -39,6 +38,27 @@ class PhxZone:
exhaust_ventilator_collection: collection.PhxExhaustVentilatorCollection = field(
default_factory=collection.PhxExhaustVentilatorCollection
)
_thermal_bridges: Dict[str, PhxComponentThermalBridge] = field(default_factory=dict)

def add_thermal_bridges(
self,
_thermal_bridges: Union[
PhxComponentThermalBridge, Sequence[PhxComponentThermalBridge]
],
) -> None:
"""Add a new PhxComponentThermalBridge (or list of Bridges) to the PhxZone."""
if not isinstance(_thermal_bridges, Sequence):
_thermal_bridges = (_thermal_bridges,)

for tb in _thermal_bridges:
self._thermal_bridges[tb.identifier] = tb

return None

@property
def thermal_bridges(self) -> ValuesView[PhxComponentThermalBridge]:
"""Return all of the PhxComponentThermalBridge objects in the PhxZone."""
return self._thermal_bridges.values()

def __post_init__(self) -> None:
self.__class__._count += 1
Expand All @@ -49,7 +69,6 @@ def __post_init__(self) -> None:
class PhxBuilding:
_components: List[PhxComponentOpaque] = field(default_factory=list)
zones: List[PhxZone] = field(default_factory=list)
_thermal_bridges: Dict[str, PhxComponentThermalBridge] = field(default_factory=dict)

@property
def weighted_net_floor_area(self) -> float:
Expand Down Expand Up @@ -79,21 +98,6 @@ def add_zones(self, _zones: Union[PhxZone, Sequence[PhxZone]]) -> None:
for zone in _zones:
self.zones.append(zone)

def add_thermal_bridges(
self,
_thermal_bridges: Union[
PhxComponentThermalBridge, Sequence[PhxComponentThermalBridge]
],
) -> None:
"""Add a new PhxComponentThermalBridge (or list of Bridges) to the PhxBuilding."""
if not isinstance(_thermal_bridges, Sequence):
_thermal_bridges = (_thermal_bridges,)

for tb in _thermal_bridges:
self._thermal_bridges[tb.identifier] = tb

return None

def merge_opaque_components_by_assembly(self) -> None:
"""Merge together all the Opaque-Components in the Building if they gave the same Attributes."""
# -- Group the opaque components by their unique key / type
Expand Down Expand Up @@ -169,11 +173,6 @@ def shading_components(self) -> List[PhxComponentOpaque]:
[c for c in self._components if c.is_shade], key=lambda _: _.display_name
)

@property
def thermal_bridges(self) -> ValuesView[PhxComponentThermalBridge]:
"""Return all of the PhxComponentThermalBridge objects in the PhxBuilding."""
return self._thermal_bridges.values()

@property
def polygon_ids(self) -> Set[int]:
"""Return a Set of all the Polygon IDs of all Polygons from all the Components in the building."""
Expand All @@ -188,6 +187,4 @@ def polygons(self) -> List[geometry.PhxPolygon]:
return [poly for component in self.all_components for poly in component.polygons]

def __bool__(self) -> bool:
return (
bool(self.opaque_components) or bool(self.zones) or bool(self.thermal_bridges)
)
return bool(self.opaque_components) or bool(self.zones)
20 changes: 20 additions & 0 deletions PHX/to_WUFI_XML/xml_schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,25 @@ def _PhxZone(_z: building.PhxZone) -> List[xml_writable]:
for i, v in enumerate(_z.exhaust_ventilator_collection.devices)
],
),
XML_List(
"ThermalBridges",
[
XML_Object(
"ThermalBridge", tb, "index", i, _schema_name="_PhxThermalBridge"
)
for i, tb in enumerate(_z.thermal_bridges)
],
),
]


def _PhxThermalBridge(_tb: components.PhxComponentThermalBridge) -> List[xml_writable]:
return [
XML_Node("Name", _tb.display_name),
XML_Node("Type", int(_tb.group_number.value) * -1),
XML_Node("Length", _tb.length),
XML_Node("PsiValue", _tb.psi_value),
XML_Node("IdentNrOptionalClimate", -1),
]


Expand Down Expand Up @@ -250,6 +269,7 @@ def _PhxPhBuildingData(
"EnvelopeAirtightnessCoefficient",
_phius_cert.ph_building_data.airtightness_q50,
),
XML_Node("SummerHRVHumidityRecovery", 4, "choice", "Always"),
XML_List(
"FoundationInterfaces",
[
Expand Down
12 changes: 6 additions & 6 deletions _testing_to_WUFI.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@
TARGET_DIR = pathlib.Path("tests", "_reference_xml")

# -- Temp
SOURCE_FILES = [
pathlib.Path(
"/Users/em/Dropbox/bldgtyp-00/00_PH_Tools/PHX/sample/hbjson/Arverne_D_230109.hbjson"
)
]
TARGET_DIR = pathlib.Path("sample")
# SOURCE_FILES = [
# pathlib.Path(
# "/Users/em/Dropbox/bldgtyp-00/00_PH_Tools/PHX/sample/hbjson/testing_tbs.hbjson"
# )
# ]
# TARGET_DIR = pathlib.Path("sample")


def generate_xml_file(_source: pathlib.Path, _target_dir: pathlib.Path):
Expand Down
6 changes: 4 additions & 2 deletions tests/_reference_xml/Default_Model_Single_Zone.xml
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@
<Components count="3">
<Component index="0">
<IdentNr>5</IdentNr>
<Name>Room_1_8687dcf1..Face4</Name>
<Name>Room_7_7db2e0dd..Face4</Name>
<Visual>true</Visual>
<Type>1</Type>
<IdentNrColorI>12</IdentNrColorI>
Expand All @@ -207,7 +207,7 @@
</Component>
<Component index="1">
<IdentNr>6</IdentNr>
<Name>Room_1_8687dcf1..Face5</Name>
<Name>Room_7_7db2e0dd..Face5</Name>
<Visual>true</Visual>
<Type>1</Type>
<IdentNrColorI>7</IdentNrColorI>
Expand Down Expand Up @@ -262,6 +262,7 @@
<NumberBedrooms unit="-">0</NumberBedrooms>
<HomeDevice count="0"/>
<ExhaustVents count="0"/>
<ThermalBridges count="0"/>
</Zone>
</Zones>
</Building>
Expand Down Expand Up @@ -485,6 +486,7 @@
<NumberUnits>1</NumberUnits>
<CountStories>1</CountStories>
<EnvelopeAirtightnessCoefficient>0.81576</EnvelopeAirtightnessCoefficient>
<SummerHRVHumidityRecovery choice="Always">4</SummerHRVHumidityRecovery>
<FoundationInterfaces count="1">
<FoundationInterface index="0">
<Name></Name>
Expand Down
Loading

0 comments on commit 01801f6

Please sign in to comment.