Skip to content

Commit

Permalink
feat(foundations): Add support for Foundation objects, export to WUFI
Browse files Browse the repository at this point in the history
- Add new PH Foundation types
- Add WUFI-Passive export support
- Add new tests
  • Loading branch information
ed-p-may committed Mar 18, 2023
1 parent 71aa98b commit 5d61156
Show file tree
Hide file tree
Showing 14 changed files with 735 additions and 414 deletions.
30 changes: 30 additions & 0 deletions PHX/from_HBJSON/cleanup.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

try:
from honeybee_ph.properties.room import RoomPhProperties
from honeybee_ph.foundations import PhFoundation
except ImportError as e:
raise ImportError("\nFailed to import honeybee_ph:\n\t{}".format(e))

Expand Down Expand Up @@ -350,6 +351,34 @@ def check_room_has_spaces(_hb_room: room.Room) -> None:
)


def merge_foundations(_hb_rooms: List[room.Room]) -> Dict[str, PhFoundation]:
"""
Arguments:
----------
*
Returns:
--------
*
"""

# -- Group by Identifier
foundation_groups = {}
for rm in _hb_rooms:
for foundation in rm.properties.ph.ph_foundations:
foundation_groups[foundation.identifier] = foundation

# -- Warn if more than 3 of them
if len(foundation_groups) > 3:
msg = f"\tWarning: WUFI-Passive only allows 3 Foundation types. "\
f" {len(foundation_groups)} found on the Building Segment '"\
f"{_hb_rooms[0].properties.ph.ph_bldg_segment.display_name}'?"
print(msg)

return foundation_groups


def merge_rooms(_hb_rooms: List[room.Room]) -> room.Room:
"""Merge together a group of Honeybee Rooms into a new single HB Room.
Expand Down Expand Up @@ -389,6 +418,7 @@ def merge_rooms(_hb_rooms: List[room.Room]) -> room.Room:
ref_rm_prop_ph: RoomPhProperties = reference_room.properties.ph # type: ignore
new_rm_prop_ph: RoomPhProperties = new_room.properties.ph # type: ignore
dup_ph_prop = ref_rm_prop_ph.duplicate(new_rm_prop_ph, include_spaces=False)
dup_ph_prop._ph_foundations = merge_foundations(_hb_rooms)
setattr(new_room._properties, "_ph", dup_ph_prop)

ref_rm_prop_energy: RoomEnergyProperties = reference_room.properties.energy # type: ignore
Expand Down
54 changes: 54 additions & 0 deletions PHX/from_HBJSON/create_foundations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
# -*- Python Version: 3.7 -*-

"""Functions to build PHX-Foundations from HBPH source objects."""

from typing import Dict
from honeybee_ph.foundations import PhFoundation

from PHX.model.enums.foundations import FoundationType
from PHX.model import ground

def create_phx_foundation_from_hbph(_hbph_foundation: PhFoundation) -> ground.PhxFoundation:
"""Return a new PhxFoundation object with attributes based on a source HBPH-Foundation.
Arguments:
----------
*
Returns:
--------
* (PhxFoundation)
"""

phx_foundation_type_map: Dict[str, ground.PhxFoundationTypes] = {
"PhHeatedBasement": ground.PhxHeatedBasement,
"PhUnheatedBasement": ground.PhxUnHeatedBasement,
"PhSlabOnGrade": ground.PhxSlabOnGrade,
"PhVentedCrawlspace": ground.PhxVentedCrawlspace,
"PhFoundation": ground.PhxFoundation,
}
new_phx_foundation = phx_foundation_type_map[_hbph_foundation.__class__.__name__]()
new_phx_foundation.display_name = _hbph_foundation.display_name
new_phx_foundation.foundation_type_num = FoundationType(_hbph_foundation.foundation_type.number)


# -- Pull out all the PH attributes and set the PHX ones to match.
for attr_name in vars(_hbph_foundation).keys():
if str(attr_name).startswith("_"):
attr_name = attr_name[1:]

try:
# try and set any Enums by number first...
setattr(new_phx_foundation, attr_name, getattr(_hbph_foundation, attr_name).number)
except AttributeError:
# ... then just set copy over any non-Enum values
try:
setattr(new_phx_foundation, attr_name, getattr(_hbph_foundation, attr_name))
except KeyError:
raise
except Exception as e:
msg = f"\n\tError setting attribute '{attr_name}' on '{new_phx_foundation.__class__.__name__}'?"
raise Exception(msg)

return new_phx_foundation
19 changes: 10 additions & 9 deletions PHX/from_HBJSON/create_variant.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@
from typing import Dict, Set

from honeybee import room

from honeybee_ph import site, phi, phius, space

from honeybee_energy.properties.room import RoomEnergyProperties

from honeybee_ph import site, phi, phius, space
from honeybee_ph.properties.room import RoomPhProperties

from honeybee_energy_ph.properties.load import equipment, people
from honeybee_energy_ph.properties.hvac.idealair import IdealAirSystemPhProperties
from honeybee_energy_ph.properties.hot_water.hw_system import SHWSystemPhProperties
Expand All @@ -22,14 +21,14 @@
_ExhaustVentilatorBase,
)

from PHX.model import phx_site, project, ground, constructions, certification
from PHX.model import phx_site, project, constructions, certification
from PHX.model.utilization_patterns import UtilizationPatternCollection_Ventilation
from PHX.model.enums import (
phi_certification_phpp_9,
phi_certification_phpp_10,
phius_certification,
)
from PHX.from_HBJSON import create_building, create_hvac, create_elec_equip
from PHX.from_HBJSON import create_building, create_hvac, create_elec_equip, create_foundations
from PHX.from_HBJSON.create_shw import (
build_phx_piping,
build_phx_piping,
Expand Down Expand Up @@ -290,10 +289,12 @@ def add_PhxPhBuildingData_from_hb_room(
if hb_prop_energy.people:
hb_ppl_prop_ph: people.PeoplePhProperties = hb_prop_energy.people.properties.ph # type: ignore
ph_bldg.num_of_units = hb_ppl_prop_ph.number_dwelling_units
ph_bldg.num_of_floors = _hb_room.properties.ph.ph_bldg_segment.num_floor_levels # type: ignore

# TODO: Foundations. For now: set to None
ph_bldg.add_foundation(ground.PhxFoundation())
ph_bldg.num_of_floors = hb_prop_ph.ph_bldg_segment.num_floor_levels # type: ignore

# -- Add Foundations
for hbph_foundation in hb_prop_ph.ph_foundations:
phx_foundation = create_foundations.create_phx_foundation_from_hbph(hbph_foundation)
ph_bldg.add_foundation(phx_foundation)

# -- Set the airtightness for Building
ph_bldg.airtightness_q50 = hb_prop_energy.infiltration.flow_per_exterior_area * 3600
Expand Down
22 changes: 22 additions & 0 deletions PHX/model/enums/foundations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# -*- Python Version: 3.7 -*-

"""Valid 'types' for Foundation Options and Types"""

from enum import Enum


class CalculationSetting(Enum):
USER_DEFINED = 6

class FoundationType(Enum):
HEATED_BASEMENT = 1
UNHEATED_BASEMENT = 2
SLAB_ON_GRADE = 3
VENTED_CRAWLSPACE = 4
NONE = 5

class PerimeterInsulationPosition(Enum):
UNDEFINED = 1
HORIZONTAL = 2
VERTICAL = 3
84 changes: 80 additions & 4 deletions PHX/model/ground.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,89 @@

"""PHX Foundation Class"""

from typing import Union, Type
from dataclasses import dataclass
from PHX.model.enums.foundations import FoundationType, CalculationSetting, PerimeterInsulationPosition


@dataclass
class PhxFoundation:
floor_setting_num: int = 6 # User Defined
floor_setting_str: str = "User defined"
display_name: str = "__unnamed_foundation__"

floor_type_num: int = 5
floor_type_str: str = "None"
foundation_setting_num: CalculationSetting = CalculationSetting.USER_DEFINED
_foundation_type_num: FoundationType = FoundationType.NONE

@property
def foundation_type_num(self) -> FoundationType:
return self._foundation_type_num

@foundation_type_num.setter
def foundation_type_num(self, _input):
self._foundation_type_num = FoundationType(_input)


class PhxHeatedBasement(PhxFoundation):
def __init__(self):
super().__init__()
self.floor_slab_area_m2: float = 0.0
self.floor_slab_u_value: float = 1.0
self.floor_slab_exposed_perimeter_m: float = 0.0
self.slab_depth_below_grade_m: float = 2.5
self.basement_wall_u_value: float = 1.0


class PhxUnHeatedBasement(PhxFoundation):
def __init__(self):
super().__init__()
self.floor_ceiling_area_m2: float = 0.0
self.ceiling_u_value: float = 0.0
self.floor_slab_exposed_perimeter_m: float = 0.0
self.slab_depth_below_grade_m: float = 0.0
self.basement_wall_height_above_grade_m: float = 0.0
self.basement_wall_uValue_below_grade: float = 0.0
self.basement_wall_uValue_above_grade: float = 0.0
self.floor_slab_u_value: float = 0.0
self.basement_volume_m3: float = 0.0
self.basement_ventilation_ach: float = 0.0


class PhxSlabOnGrade(PhxFoundation):
def __init__(self):
super().__init__()
self.floor_slab_area_m2: float = 0.0
self.floor_slab_u_value: float = 1.0
self.floor_slab_exposed_perimeter_m: float = 0.0
self._perim_insulation_position: PerimeterInsulationPosition = PerimeterInsulationPosition.VERTICAL
self.perim_insulation_width_or_depth_m: float = 0.300
self.perim_insulation_thickness_m: float = 0.050
self.perim_insulation_conductivity: float = 0.04

@property
def perim_insulation_position(self):
return self._perim_insulation_position

@perim_insulation_position.setter
def perim_insulation_position(self, _input):
self._perim_insulation_position = PerimeterInsulationPosition(_input)


class PhxVentedCrawlspace(PhxFoundation):
def __init__(self):
super().__init__()
self.crawlspace_floor_slab_area_m2 = 0.0
self.ceiling_above_crawlspace_u_value = 1.0
self.crawlspace_floor_exposed_perimeter_m = 0.0
self.crawlspace_wall_height_above_grade_m = 0.0
self.crawlspace_floor_u_value = 1.0
self.crawlspace_vent_opening_are_m2 = 0.0
self.crawlspace_wall_u_value = 1.0


# type alias
PhxFoundationTypes = Union[
Type[PhxFoundation],
Type[PhxHeatedBasement],
Type[PhxUnHeatedBasement],
Type[PhxSlabOnGrade],
Type[PhxVentedCrawlspace]
]
Loading

0 comments on commit 5d61156

Please sign in to comment.