Skip to content

Commit

Permalink
fix(mixed-materials): Mixed-material equiv. U-Value
Browse files Browse the repository at this point in the history
- Add new equivalent-U-Value material to heterogeneous material builders
- Update installer versions
  • Loading branch information
ed-p-may committed Jan 1, 2025
1 parent e4acc9d commit 60741cb
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 53 deletions.
Binary file modified hbph_installer.gh
Binary file not shown.
2 changes: 1 addition & 1 deletion honeybee_ph_rhino/_component_info_.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
These are called when the component is instantiated within the Grasshopper canvas.
"""

RELEASE_VERSION = "Honeybee-PH v1.7.06"
RELEASE_VERSION = "Honeybee-PH v1.7.07"
CATEGORY = "HB-PH"
SUB_CATEGORIES = {
0: "00 | Utils",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@
raise ImportError("\nFailed to import honeybee_ph_rhino:\n\t{}".format(e))

try:
from honeybee_energy_ph.properties.materials.opaque import CellPositionError, EnergyMaterialPhProperties
from honeybee_energy_ph.properties.materials.opaque import (
CellPositionError,
EnergyMaterialPhProperties,
PhDivisionGrid,
)
except ImportError as e:
raise ImportError("\nFailed to import honeybee_energy_ph:\n\t{}".format(e))

Expand Down Expand Up @@ -89,6 +93,18 @@ def __init__(self, IGH, _base_material, _additional_materials, _column_widths, _
self.column_widths = _column_widths
self.row_heights = _row_heights

@property
def all_materials(self):
# type: () -> List[opaque.EnergyMaterial]
"""Get all the materials including the base and additional materials."""
mats = []
for mat in self.additional_materials:
if mat is not None:
mats.append(mat)
if self.base_material is not None:
mats.insert(0, self.base_material)
return mats

def ready(self):
# type: () -> bool
"""Check if all the inputs are ready, perform some cleanup on the inputs."""
Expand Down Expand Up @@ -175,33 +191,55 @@ def check_material_conductivities(self, material):
self.IGH.error(msg)
break

def set_cell_material(self, _division_grid, _column, _row, _material):
# type: (PhDivisionGrid, int, int, opaque.EnergyMaterial) -> None
print(
"Setting Material at: Column-{} | Row-{} to '{}' [id={}]".format(
_column, _row, _material.display_name, id(_material)
)
)
try:
_division_grid.set_cell_material(_column, _row, _material)
except CellPositionError as e:
print("- " * 25)
print("WARNING: Check the '_column_widths' and '_row_heights' inputs.\n")
raise e

def run(self):
# type: () -> Tuple[Optional[opaque.EnergyMaterial], Optional[Any]]
if not self.ready() or not self.base_material:
return (self.base_material, None)

# -- Setup the Base Material Division Grid
new_material_ = self.base_material.duplicate()
ph_prop = new_material_.properties.ph # type: EnergyMaterialPhProperties # type: ignore
# --------------------------------------------------------------------------------------------------------------
# -- Setup the Division Grid
division_grid = PhDivisionGrid()
division_grid.set_column_widths(self.column_widths)
division_grid.set_row_heights(self.row_heights)

ph_prop.divisions.set_column_widths(self.column_widths)
ph_prop.divisions.set_row_heights(self.row_heights)
for row in range(division_grid.row_count):
for col in range(division_grid.column_count):
division_grid.set_cell_material(col, row, self.base_material)

for material in self.additional_materials:
col = material.properties.ph.user_data.get("column_position", 0) # type: ignore
row = material.properties.ph.user_data.get("row_position", 0) # type: ignore
print(
"Setting Material at: Column-{} | Row-{} to '{}' [id={}]".format(
col, row, material.display_name, id(material)
)
)
try:
ph_prop.divisions.set_cell_material(col, row, material)
except CellPositionError as e:
print("- " * 25)
print("WARNING: Check the '_column_widths' and '_row_heights' inputs.\n")
raise e

hbph_mat_props = getattr(material.properties, "ph") # type: EnergyMaterialPhProperties
col = hbph_mat_props.user_data.get("column_position", 0)
row = hbph_mat_props.user_data.get("row_position", 0)
self.set_cell_material(division_grid, col, row, material)

# --------------------------------------------------------------------------------------------------------------
# -- Create a new Hybrid Material
base_material = division_grid.get_base_material()
if not base_material:
return (None, None)
new_material_ = base_material.duplicate()
nm = "+".join([_.display_name for _ in self.all_materials])
new_material_.display_name = nm
new_material_.identifier = nm
new_material_.conductivity = division_grid.get_equivalent_conductivity()
hbph_props = getattr(new_material_.properties, "ph") # type: EnergyMaterialPhProperties
hbph_props.divisions = division_grid

# --------------------------------------------------------------------------------------------------------------
self.check_material_thicknesses(new_material_)
self.check_material_conductivities(new_material_)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
raise ImportError("\nFailed to import honeybee_ph_rhino:\n\t{}".format(e))

try:
from honeybee_energy_ph.properties.materials.opaque import EnergyMaterialPhProperties
from honeybee_energy_ph.properties.materials.opaque import EnergyMaterialPhProperties, PhDivisionGrid
except ImportError as e:
raise ImportError("\nFailed to import honeybee_energy_ph:\n\t{}".format(e))

Expand Down Expand Up @@ -92,73 +92,121 @@ def default_wood_framing_material(self):
roughness="MediumRough",
thickness=0.1,
)

mat_.properties.ph.ph_color = PhColor.from_argb(255, 255, 128, 0)
hbph_props = getattr(mat_, "properties") # type: EnergyMaterialPhProperties
hbph_props.ph_color = PhColor.from_argb(255, 255, 128, 0)
return mat_

def _convert(self, value, to_unit="M"):
# type: (Union[float, int, str], str) -> float
return convert(*parse_input(value), _target_unit=to_unit) or 0.0

def check_material_type(self, _material):
# type: (opaque.EnergyMaterial) -> opaque.EnergyMaterial | None
if not isinstance(_material, opaque.EnergyMaterial):
msg = "ERROR: Material '{}' of type '{}' is not allowed. Use only EnergyMaterial.".format(
_material, type(_material)
)
print(msg)
self.IGH.error(msg)
return None
else:
return _material

def check_material_conductivity(self, _material):
# type: (opaque.EnergyMaterial) -> None
# type: (opaque.EnergyMaterial) -> opaque.EnergyMaterial | None
if _material.conductivity > 10.0:
msg = (
"WARNING: Material '{}' has a very high conductivity value of {:.2f} W/m-K. "
"ERROR: Material '{}' has a very high conductivity value of {:.2f} W/m-K. "
"Note that metal elements like steel studs and metal fasteners may NOT be "
"used as part of heterogeneous assemblies (as per ISO 6946).".format(
_material.display_name, _material.conductivity
)
)
print(msg)
self.IGH.error(msg)
return None
else:
return _material

def check_material(self, _material):
# type: (opaque.EnergyMaterial | None) -> opaque.EnergyMaterial | None
if _material is None:
return None
if not self.check_material_type(_material):
return None
if not self.check_material_conductivity(_material):
return None
return _material

def run(self):
# type: () -> Tuple[Optional[opaque.EnergyMaterial], Optional[List[Brep]]]
if self.insulation_material is None or self.wood_framing_material is None:
insulation_material = self.check_material(self.insulation_material)
if not insulation_material:
return (None, None)

# -- Check
self.check_material_conductivity(self.wood_framing_material)
self.check_material_conductivity(self.insulation_material)

# -- Setup the Division Grid
new_material_ = self.insulation_material.duplicate()
ph_prop = new_material_.properties.ph # type: EnergyMaterialPhProperties
wood_framing_material = self.check_material(self.wood_framing_material)
if not wood_framing_material:
return (None, None)

# --------------------------------------------------------------------------------------------------------------
# -- Setup the new Division Grid
division_grid = PhDivisionGrid()
insulation_width = (self.wood_framing_member_oc_spacing - self.wood_framing_member_width) / 2
ph_prop.divisions.set_column_widths(
division_grid.set_column_widths(
[
insulation_width,
self.wood_framing_member_width,
insulation_width,
]
)
ph_prop.divisions.set_row_heights(
division_grid.set_row_heights(
[
self.top_plate_width,
self.element_total_length - self.top_plate_width - self.bottom_plate_width,
self.bottom_plate_width,
]
)

# -- Set the Wood Framing Materials on the relevant cells
for row_number in range(ph_prop.divisions.row_count):
ph_prop.divisions.set_cell_material(1, row_number, self.wood_framing_material)
# --------------------------------------------------------------------------------------------------------------
# -- Set the Materials on the cells

# -- Set the 'stud' to the framing material (column-1)
for row_number in range(division_grid.row_count):
division_grid.set_cell_material(0, row_number, insulation_material)
division_grid.set_cell_material(1, row_number, wood_framing_material)
division_grid.set_cell_material(2, row_number, insulation_material)

# -- Set the top-plate
if self.top_plate_width != 0:
ph_prop.divisions.set_cell_material(0, 0, self.wood_framing_material)
ph_prop.divisions.set_cell_material(2, 0, self.wood_framing_material)
division_grid.set_cell_material(0, 0, wood_framing_material)
division_grid.set_cell_material(1, 0, wood_framing_material)
division_grid.set_cell_material(2, 0, wood_framing_material)

# -- Set the bottom-plate
if self.bottom_plate_width != 0:
ph_prop.divisions.set_cell_material(0, ph_prop.divisions.row_count - 1, self.wood_framing_material)
ph_prop.divisions.set_cell_material(2, ph_prop.divisions.row_count - 1, self.wood_framing_material)

division_grid.set_cell_material(0, division_grid.row_count - 1, wood_framing_material)
division_grid.set_cell_material(1, division_grid.row_count - 1, wood_framing_material)
division_grid.set_cell_material(2, division_grid.row_count - 1, wood_framing_material)

# --------------------------------------------------------------------------------------------------------------
# -- Create a new Hybrid Material
base_material = division_grid.get_base_material()
if not base_material:
return (None, None)
new_material_ = base_material.duplicate()
nm = "{} + {}".format(insulation_material.display_name, wood_framing_material.display_name)
new_material_.display_name = nm
new_material_.identifier = nm
new_material_.conductivity = division_grid.get_equivalent_conductivity()
hbph_props = getattr(new_material_.properties, "ph") # type: EnergyMaterialPhProperties
hbph_props.divisions = division_grid

# --------------------------------------------------------------------------------------------------------------
# -- Generate the Preview
preview_ = generate_preview(
self.IGH,
convert_list_of_values(ph_prop.divisions.column_widths, self.IGH.get_rhino_unit_system_name()),
convert_list_of_values(ph_prop.divisions.row_heights, self.IGH.get_rhino_unit_system_name()),
convert_list_of_values(division_grid.column_widths, self.IGH.get_rhino_unit_system_name()),
convert_list_of_values(division_grid.row_heights, self.IGH.get_rhino_unit_system_name()),
)

return new_material_, preview_
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def run(self):
row_position = gh_io.input_to_int(str(self.row_position))

hbe_material_ = self.hbe_material.duplicate()
ph_prop = hbe_material_.properties.ph # type: EnergyMaterialPhProperties
ph_prop = getattr(hbe_material_.properties, "ph") # type: EnergyMaterialPhProperties

if not hasattr(ph_prop, "user_data"):
ph_prop.user_data = {}
Expand Down
12 changes: 6 additions & 6 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
honeybee-core>=1.58.53
honeybee-energy>=1.109.6
ladybug-rhino>=1.42.17
honeybee-ph>=1.28.15
PHX>=1.47.6
PH-units>=1.5.14
honeybee-core>=1.61.1
honeybee-energy>=1.111.0
ladybug-rhino>=1.43.1
honeybee-ph>=1.28.20
PHX>=1.48.0
PH-units>=1.5.17

0 comments on commit 60741cb

Please sign in to comment.