diff --git a/README.md b/README.md
index 0849154..d042031 100644
--- a/README.md
+++ b/README.md
@@ -4,13 +4,9 @@ Honeybee-PH plugins and components for Rhino / Grasshopper.
-This repository contains all PH (Passive House) modeling Grasshopper components for the Honeybee-PH
-plugin. The package includes both the userobjects (`.ghuser`) and the Python
-source (`.py`). Note that this library only possesses the Grasshopper components
-and. On order to run the plugin the core Honeybee AND Honeybee-PH / PHX libraries must be installed in a way that
-they can be found by Rhino (see dependencies and install instructions below).
+This repository contains all PH (Passive House) modeling Grasshopper components for the Honeybee-PH plugin. Once installed, these new Grasshopper components will allow you to add detailed 'Passive House' style data to your Honeybee models, and to export the Honeybee models to both the Passive House Planning Package (PHPP) and WUFI-Passive. The package includes both the userobjects (`.ghuser`) and the Python source (`.py`). Note that this library only possesses the Grasshopper components. In order to use the plugin the core Honeybee, Honeybee-PH and PHX libraries must also be installed in a way that they can be found by Rhino (see dependencies and install instructions below).
-More information, examples and tutorials can be found on the [Honeybee-PH](https://ph-tools.github.io/honeybee_grasshopper_ph/) page.
+More information, examples, and tutorials can be found on the [Honeybee-PH](https://ph-tools.github.io/honeybee_grasshopper_ph/) page.
# How To Install honeybee-grasshoper-ph:
See the [Honeybee-PH Installation](https://ph-tools.github.io/honeybee_grasshopper_ph/install/) page for more information on how to add this package to your system.
@@ -19,7 +15,7 @@ Check out the [detailed installation walkthrough on YouTube](https://youtu.be/Dv
## Dependencies
-The honeybee-grasshopper-ph plugin has the following dependencies on core libraries:
+The honeybee-grasshopper-ph plugin has the following package dependencies:
* [ladybug-core](https://github.com/ladybug-tools/ladybug)
* [ladybug-geometry](https://github.com/ladybug-tools/ladybug-geometry)
diff --git a/hbph_installer.gh b/hbph_installer.gh
index 3e4dc7c..5644724 100644
Binary files a/hbph_installer.gh and b/hbph_installer.gh differ
diff --git a/honeybee_grasshopper_ph/src/HBPH - Add Foundations.py b/honeybee_grasshopper_ph/src/HBPH - Add Foundations.py
new file mode 100644
index 0000000..d1945f1
--- /dev/null
+++ b/honeybee_grasshopper_ph/src/HBPH - Add Foundations.py
@@ -0,0 +1,71 @@
+#
+# Honeybee-PH: A Plugin for adding Passive-House data to LadybugTools Honeybee-Energy Models
+#
+# This component is part of the PH-Tools toolkit .
+#
+# Copyright (c) 2022, PH-Tools and bldgtyp, llc
+# Honeybee-PH is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published
+# by the Free Software Foundation; either version 3 of the License,
+# or (at your option) any later version.
+#
+# Honeybee-PH is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For a copy of the GNU General Public License
+# see .
+#
+# @license GPL-3.0+
+#
+"""
+Add PH-Foundation objects to the Honeybee-Rooms. Note that
+PHPP only allows 3 different Foundation types per Building-Segment.
+-
+EM March 18, 2023
+ Args:
+ _ph_foundation: One or more PH-Foundation Objects that you would like
+ to add to each of the Honyebee-Rooms input.
+
+ _hb_rooms: List[room.Room] One or more Honeybee-Rooms you would like to
+ add the new PH-Foundations to.
+
+ Returns:
+ hb_rooms_: The honeyee-Rooms with building-segment information added.
+"""
+
+import scriptcontext as sc
+import Rhino as rh
+import rhinoscriptsyntax as rs
+import ghpythonlib.components as ghc
+import Grasshopper as gh
+
+
+try:
+ from honeybee_ph_rhino import gh_compo_io, gh_io
+except ImportError as e:
+ raise ImportError('Failed to import honeybee_ph_rhino:\t{}'.format(e))
+
+
+# -------------------------------------------------------------------------------------
+import honeybee_ph_rhino._component_info_
+reload(honeybee_ph_rhino._component_info_)
+ghenv.Component.Name = "HBPH - Add Foundations"
+DEV = honeybee_ph_rhino._component_info_.set_component_params(ghenv, dev=False)
+if DEV:
+ from honeybee_ph_rhino.gh_compo_io import foundations_add as gh_compo_io
+ reload(gh_compo_io)
+
+# -------------------------------------------------------------------------------------
+# -- GH Interface
+IGH = gh_io.IGH( ghdoc, ghenv, sc, rh, rs, ghc, gh )
+
+
+# -------------------------------------------------------------------------------------
+gh_compo_interface = gh_compo_io.GHCompo_AddFoundations(
+ IGH,
+ _ph_foundations,
+ _hb_rooms,
+)
+hb_rooms_ = gh_compo_interface.run()
diff --git a/honeybee_grasshopper_ph/src/HBPH - Create Foundation.py b/honeybee_grasshopper_ph/src/HBPH - Create Foundation.py
new file mode 100644
index 0000000..a38aad6
--- /dev/null
+++ b/honeybee_grasshopper_ph/src/HBPH - Create Foundation.py
@@ -0,0 +1,92 @@
+#
+# Honeybee-PH: A Plugin for adding Passive-House data to LadybugTools Honeybee-Energy Models
+#
+# This component is part of the PH-Tools toolkit .
+#
+# Copyright (c) 2022, PH-Tools and bldgtyp, llc
+# Honeybee-PH is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published
+# by the Free Software Foundation; either version 3 of the License,
+# or (at your option) any later version.
+#
+# Honeybee-PH is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For a copy of the GNU General Public License
+# see .
+#
+# @license GPL-3.0+
+#
+"""
+Create a new PH-Foundation object which can be added to one or more Honeybee-Rooms.
+-
+EM March 18, 2023
+ Args:
+ _type: (str) The Type of foundation. Input either-
+"1-Heated Basement"
+"2-Unheated Basement"
+"3-Slab on Grade"
+"4-Vented Crawlspace"
+"5-None"
+
+ Returns:
+ ph_foundation: The new PH-Foundation object which can be added to one
+ or more Honeybee-Rooms using the "HBPH - Add Foundations" component.
+"""
+
+import scriptcontext as sc
+import Rhino as rh
+import rhinoscriptsyntax as rs
+import ghpythonlib.components as ghc
+import Grasshopper as gh
+
+
+try:
+ from honeybee_ph_utils import preview
+except ImportError as e:
+ raise ImportError('Failed to import honeybee_ph_utils:\t{}'.format(e))
+
+try:
+ from honeybee_ph_rhino import gh_compo_io, gh_io
+ from honeybee_ph_rhino.gh_compo_io.foundations_create import get_component_inputs
+except ImportError as e:
+ raise ImportError('Failed to import honeybee_ph_rhino:\t{}'.format(e))
+
+
+# -------------------------------------------------------------------------------------
+import honeybee_ph_rhino._component_info_
+reload(honeybee_ph_rhino._component_info_)
+ghenv.Component.Name = "HBPH - Create Foundation"
+DEV = honeybee_ph_rhino._component_info_.set_component_params(ghenv, dev=False)
+if DEV:
+ from honeybee_ph import foundations
+ reload(foundations)
+ from honeybee_ph_rhino.gh_compo_io import foundations_create as gh_compo_io
+ reload(gh_compo_io)
+
+
+# -------------------------------------------------------------------------------------
+# -- GH Interface
+IGH = gh_io.IGH( ghdoc, ghenv, sc, rh, rs, ghc, gh )
+
+
+#-------------------------------------------------------------------------------
+# -- Setup the input nodes, get all the user input values
+input_dict = get_component_inputs(_type)
+gh_io.setup_component_inputs(IGH, input_dict, _start_i=2)
+input_values_dict = gh_io.get_component_input_values(ghenv)
+
+
+# -------------------------------------------------------------------------------------
+gh_compo_interface = gh_compo_io.GHCompo_CreateFoundations(
+ IGH,
+ _type,
+ input_values_dict,
+)
+ph_foundation_ = gh_compo_interface.run()
+
+
+# -------------------------------------------------------------------------------------
+preview.object_preview(ph_foundation_)
diff --git a/honeybee_grasshopper_ph/user_objects/HBPH - Add Foundations.ghuser b/honeybee_grasshopper_ph/user_objects/HBPH - Add Foundations.ghuser
new file mode 100644
index 0000000..81d57dc
Binary files /dev/null and b/honeybee_grasshopper_ph/user_objects/HBPH - Add Foundations.ghuser differ
diff --git a/honeybee_grasshopper_ph/user_objects/HBPH - Create Foundation.ghuser b/honeybee_grasshopper_ph/user_objects/HBPH - Create Foundation.ghuser
new file mode 100644
index 0000000..371140a
Binary files /dev/null and b/honeybee_grasshopper_ph/user_objects/HBPH - Create Foundation.ghuser differ
diff --git a/honeybee_ph_rhino/_component_info_.py b/honeybee_ph_rhino/_component_info_.py
index 45de7b0..54fb203 100644
--- a/honeybee_ph_rhino/_component_info_.py
+++ b/honeybee_ph_rhino/_component_info_.py
@@ -5,7 +5,7 @@
These are called when the component is instantiated within the Grasshopper canvas.
"""
-RELEASE_VERSION = "Honeybee-PH v1.0.24"
+RELEASE_VERSION = "Honeybee-PH v1.0.25"
CATEGORY = "HB-PH"
SUB_CATEGORIES = {
0: "00 | Utils",
@@ -387,6 +387,19 @@
"Category": CATEGORY,
"SubCategory": 4,
},
+ # -- Foundations
+ "HBPH - Add Foundations": {
+ "NickName": "Add Foundations",
+ "Message": RELEASE_VERSION,
+ "Category": CATEGORY,
+ "SubCategory": 4,
+ },
+ "HBPH - Create Foundation": {
+ "NickName": "Create Foundation",
+ "Message": RELEASE_VERSION,
+ "Category": CATEGORY,
+ "SubCategory": 4,
+ },
}
diff --git a/honeybee_ph_rhino/gh_compo_io/__init__.py b/honeybee_ph_rhino/gh_compo_io/__init__.py
index 1766979..a09146e 100644
--- a/honeybee_ph_rhino/gh_compo_io/__init__.py
+++ b/honeybee_ph_rhino/gh_compo_io/__init__.py
@@ -63,3 +63,6 @@
# -- Export
from honeybee_ph_rhino.gh_compo_io.write_wuif_xml import GHCompo_WriteWufiXml
from honeybee_ph_rhino.gh_compo_io.write_PHPP import GHCompo_WriteToPHPP
+# -- Foundations
+from honeybee_ph_rhino.gh_compo_io.foundations_add import GHCompo_AddFoundations
+from honeybee_ph_rhino.gh_compo_io.foundations_create import GHCompo_CreateFoundations
\ No newline at end of file
diff --git a/honeybee_ph_rhino/gh_compo_io/foundations_add.py b/honeybee_ph_rhino/gh_compo_io/foundations_add.py
new file mode 100644
index 0000000..25cca24
--- /dev/null
+++ b/honeybee_ph_rhino/gh_compo_io/foundations_add.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+# -*- Python Version: 2.7 -*-
+
+"""GHCompo Interface: HBPH - Add Foundations."""
+
+try:
+ from typing import List
+except ImportError:
+ pass # IronPython 2.7
+
+try:
+ from honeybee_ph_rhino import gh_io
+except ImportError as e:
+ raise ImportError('\nFailed to import honeybee_ph_rhino:\n\t{}'.format(e))
+
+try:
+ from honeybee import room
+except ImportError as e:
+ raise ImportError('\nFailed to import honeybee:\n\t{}'.format(e))
+
+try:
+ from honeybee_ph.foundations import PhFoundation
+except ImportError as e:
+ raise ImportError('\nFailed to import honeybee_ph:\n\t{}'.format(e))
+
+
+class GHCompo_AddFoundations(object):
+
+ def __init__(self, _IGH, _foundations, _hb_rooms):
+ # type: (gh_io.IGH, List[PhFoundation], List[room.Room]) -> None
+ self.IGH = _IGH
+ self.foundations = _foundations
+ self.hb_rooms = _hb_rooms
+
+ def run(self):
+ # type: () -> List[room.Room]
+ hb_rooms_ = []
+ for hb_room in self.hb_rooms:
+ new_hb_room = hb_room.duplicate()
+
+ for ph_foundation in self.foundations:
+ new_hb_room.properties.ph.add_foundation(ph_foundation)
+
+ hb_rooms_.append(new_hb_room)
+
+ return hb_rooms_
diff --git a/honeybee_ph_rhino/gh_compo_io/foundations_create.py b/honeybee_ph_rhino/gh_compo_io/foundations_create.py
new file mode 100644
index 0000000..c9dead7
--- /dev/null
+++ b/honeybee_ph_rhino/gh_compo_io/foundations_create.py
@@ -0,0 +1,250 @@
+# -*- coding: utf-8 -*-
+# -*- Python Version: 2.7 -*-
+
+"""GHCompo Interface: HBPH - Create Foundation."""
+
+from copy import copy
+
+try:
+ from typing import List, Dict, Any, Type, Union
+except ImportError:
+ pass # IronPython 2.7
+
+try:
+ from GhPython import Component # type: ignore
+ from Grasshopper.Kernel.Parameters import Hints # type: ignore
+except ImportError:
+ pass # Outside Grasshopper
+
+try:
+ from honeybee_ph import foundations
+except ImportError as e:
+ raise ImportError('\nFailed to import honeybee_ph:\n\t{}'.format(e))
+
+try:
+ from honeybee_ph_rhino import gh_io
+ from honeybee_ph_rhino.gh_io import ComponentInput
+except ImportError as e:
+ raise ImportError('\nFailed to import honeybee_ph_rhino:\n\t{}'.format(e))
+
+try:
+ from honeybee_ph_utils.input_tools import input_to_int
+except ImportError as e:
+ raise ImportError('\nFailed to import honeybee_ph_utils:\n\t{}'.format(e))
+
+# -----------------------------------------------------------------------------
+# -- Setup the component input node groups
+
+inputs_base = {
+ 1: ComponentInput(_name='_display_name',
+ _description='(str) Optional display-name for the Foundation.',
+ _type_hint=Component.NewStrHint()),
+}
+
+inputs_heated_basement = copy(inputs_base)
+inputs_heated_basement.update({
+ 2: ComponentInput(_name='floor_slab_area_m2',
+ _description='(float) M2 area of the floor slab.',
+ _type_hint=Component.NewFloatHint()),
+ 3: ComponentInput(_name='floor_slab_u_value',
+ _description='(float) U-Value (W/m2k) of the floor slab.',
+ _type_hint=Component.NewFloatHint()),
+ 4: ComponentInput(_name='floor_slab_exposed_perimeter_m',
+ _description='(float) Input the total length (m) of the exposed perimeter edges.',
+ _type_hint=Component.NewFloatHint()),
+ 5: ComponentInput(_name='slab_depth_below_grade_m',
+ _description='(float) The average depth (m) of the top of the floor slab below grade.',
+ _type_hint=Component.NewFloatHint()),
+ 6: ComponentInput(_name='basement_wall_u_value',
+ _description='(float) The U-Value (W/m2k) of the basement wall below grade.',
+ _type_hint=Component.NewFloatHint()),
+})
+
+inputs_unheated_basement = copy(inputs_base)
+inputs_unheated_basement.update({
+ 2: ComponentInput(_name='floor_ceiling_area_m2',
+ _description='(float) M2 area of the floor / ceiling.',
+ _type_hint=Component.NewFloatHint()),
+ 3: ComponentInput(_name='ceiling_u_value',
+ _description='(float) U-Value (W/m2k) of the ceiling above the cellar.',
+ _type_hint=Component.NewFloatHint()),
+ 4: ComponentInput(_name='floor_slab_exposed_perimeter_m',
+ _description='(float) Input the total length (m) of the exposed perimeter edges.',
+ _type_hint=Component.NewFloatHint()),
+ 5: ComponentInput(_name='slab_depth_below_grade_m',
+ _description='(float) The average depth (m) of the top of the floor slab below grade.',
+ _type_hint=Component.NewFloatHint()),
+ 6: ComponentInput(_name='basement_wall_height_above_grade_m',
+ _description='(float) The average height (m) of the basement wall above grade.',
+ _type_hint=Component.NewFloatHint()),
+ 7: ComponentInput(_name='basement_wall_uValue_below_grade',
+ _description='(float) The U-Value (W/m2k) of the basement wall below grade.',
+ _type_hint=Component.NewFloatHint()),
+ 8: ComponentInput(_name='basement_wall_uValue_above_grade',
+ _description='(float) The U-Value (W/m2k) of the basement wall above grade.',
+ _type_hint=Component.NewFloatHint()),
+ 9: ComponentInput(_name='floor_slab_u_value',
+ _description='(float) U-Value (W/m2k) of the floor slab.',
+ _type_hint=Component.NewFloatHint()),
+ 10: ComponentInput(_name='basement_volume_m3',
+ _description='(float) The Volume (m3) of the basement space.',
+ _type_hint=Component.NewFloatHint()),
+ 11: ComponentInput(_name='basement_ventilation_ach',
+ _description='(float) The ACH of the basement space. Typical=0.5 ACH',
+ _type_hint=Component.NewFloatHint()),
+})
+
+inputs_slab_on_grade = copy(inputs_base)
+inputs_slab_on_grade.update({
+ 2: ComponentInput(_name='floor_slab_area_m2',
+ _description='(float) M2 area of the floor slab.',
+ _type_hint=Component.NewFloatHint()),
+ 3: ComponentInput(_name='floor_slab_u_value',
+ _description='(float) U-Value (W/m2k) of the floor slab.',
+ _type_hint=Component.NewFloatHint()),
+ 4: ComponentInput(_name='floor_slab_exposed_perimeter_m',
+ _description='(float) Input the total length (m) of the exposed perimeter edges.',
+ _type_hint=Component.NewFloatHint()),
+ 5: ComponentInput(_name='perim_insulation_position',
+ _description='(str) Input either - "1-Undefined"\n"2-Horizontal"\n"3-Vertical"',
+ _type_hint=Hints.GH_IntegerHint_CS()),
+ 6: ComponentInput(_name='perim_insulation_width_or_depth_m',
+ _description='(float) The width (m) (if horizontal) or depth (if vertical) of the perimeter insulation.',
+ _type_hint=Component.NewFloatHint()),
+ 7: ComponentInput(_name='perim_insulation_thickness_m',
+ _description='(float) The thickness (m) of the perimeter insulation.',
+ _type_hint=Component.NewFloatHint()),
+ 8: ComponentInput(_name='perim_insulation_conductivity',
+ _description='(float) The thermal conductivity (W/mk) of the perimeter insulation.',
+ _type_hint=Component.NewFloatHint()),
+})
+
+inputs_vented_crawlspace = copy(inputs_base)
+inputs_vented_crawlspace.update({
+ 2: ComponentInput(_name='crawlspace_floor_slab_area_m2',
+ _description='(float) M2 area of the crawlspace floor.',
+ _type_hint=Component.NewFloatHint()),
+ 3: ComponentInput(_name='ceiling_above_crawlspace_u_value',
+ _description='(float) U-Value (W/m2k) of the ceiling above the crawlspace.',
+ _type_hint=Component.NewFloatHint()),
+ 4: ComponentInput(_name='crawlspace_floor_exposed_perimeter_m',
+ _description='(float) Input the total length (m) of the exposed perimeter edges of the crawlspace floor.',
+ _type_hint=Component.NewFloatHint()),
+ 5: ComponentInput(_name='crawlspace_wall_height_above_grade_m',
+ _description='(float) The average height (m) of the crawlspace wall above grade.',
+ _type_hint=Component.NewFloatHint()),
+ 6: ComponentInput(_name='crawlspace_floor_u_value',
+ _description='(float) The U-Value (W/m2k) of the crawlspace floor.',
+ _type_hint=Component.NewFloatHint()),
+ 7: ComponentInput(_name='crawlspace_vent_opening_are_m2',
+ _description='(float) The total area (m2) of the crawlspace ventilation openings.',
+ _type_hint=Component.NewFloatHint()),
+ 8: ComponentInput(_name='crawlspace_wall_u_value',
+ _description='(float) The U-Value (W/m2k) of the crawlspace wall.',
+ _type_hint=Component.NewFloatHint()),
+})
+
+inputs_none = copy(inputs_base)
+inputs_none.update({})
+
+# -----------------------------------------------------------------------------
+
+input_groups = {
+ 1: inputs_heated_basement,
+ 2: inputs_unheated_basement,
+ 3: inputs_slab_on_grade,
+ 4: inputs_vented_crawlspace,
+ 5: inputs_none,
+}
+
+# -----------------------------------------------------------------------------
+
+def get_component_inputs(_equipment_type):
+ # type: (str) -> Dict[int, ComponentInput]
+ """Select the component input-node group based on the 'type' specified"""
+
+ if not _equipment_type:
+ return {}
+
+ input_type_id = input_to_int(_equipment_type)
+
+ if not input_type_id:
+ raise Exception(
+ 'Error: Foundation type: "{}" is not a valid equip type.'.format(input_type_id)
+ )
+
+ try:
+ return input_groups[input_type_id]
+ except KeyError:
+ raise Exception(
+ 'Error: Foundation type: "{}" is not a valid equip type.'.format(input_type_id)
+ )
+
+
+# -----------------------------------------------------------------------------
+# Component Interface
+
+class GHCompo_CreateFoundations(object):
+
+ foundation_classes = {
+ 1: foundations.PhHeatedBasement,
+ 2: foundations.PhUnheatedBasement,
+ 3: foundations.PhSlabOnGrade,
+ 4: foundations.PhVentedCrawlspace,
+ 5: foundations.PhFoundation,
+ }
+
+ valid_foundation_types = ["1-HEATED_BASEMENT", "2-UNHEATED_BASEMENT", "3-SLAB_ON_GRADE", "4-VENTED_CRAWLSPACE", "5-NONE",]
+
+ def __init__(self, _IGH, _type, _input_dict):
+ # type: (gh_io.IGH, int, Dict[str, Any]) -> None
+ self.IGH = _IGH
+ self._foundation_type = _type
+ self.input_dict = _input_dict
+
+ @property
+ def foundation_type(self):
+ # type: () -> int
+ if not self._foundation_type:
+ msg = "Set the '_type' to configure the user-inputs."
+ self.IGH.warning(msg)
+ return 5
+
+ return int(self._foundation_type)
+
+ @foundation_type.setter
+ def foundation_type(self, _in):
+ # type: (Union[str, int]) -> None
+ self._foundation_type = input_to_int(_in)
+
+ @property
+ def foundation_class(self):
+ # type: () -> Type[foundations.PhFoundation]
+ try:
+ return self.foundation_classes[self.foundation_type]
+ except KeyError as e:
+ raise Exception(
+ "Error: Input foundation type: '{}' not supported. Please only input: "\
+ "{}".format(self.foundation_type, self.valid_foundation_types)
+ )
+
+
+ def run(self):
+ # type: () -> foundations.PhFoundation
+ """Return a new PhFoundation object with attributes based on the user-inputs."""
+
+ # -- Create the new PhFoundation Object
+ hbph_foundation_obj_ = self.foundation_class()
+ hbph_foundation_obj_.display_name = self.input_dict["_display_name"]
+
+ # -- Set all the new PhFoundation Object's attributes from user-inputs
+ for attr_name in dir(hbph_foundation_obj_):
+
+ if attr_name.startswith('_'):
+ continue
+
+ input_val = self.input_dict.get(attr_name)
+ if input_val:
+ setattr(hbph_foundation_obj_, attr_name, input_val)
+
+ return hbph_foundation_obj_