Skip to content

Commit

Permalink
feat(simulate): Add a component to create an empty OSM for Ironbug
Browse files Browse the repository at this point in the history
  • Loading branch information
chriswmackey authored and Chris Mackey committed May 29, 2024
1 parent 687e499 commit ebd3423
Show file tree
Hide file tree
Showing 4 changed files with 220 additions and 0 deletions.
Binary file added honeybee_grasshopper_energy/icon/HB Empty OSM.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
64 changes: 64 additions & 0 deletions honeybee_grasshopper_energy/json/HB_Empty_OSM.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"version": "1.8.0",
"nickname": "EmptyOSM",
"outputs": [
[
{
"access": "None",
"name": "osw",
"description": "File path to the OpenStudio Workflow JSON on this machine. This workflow\nis executed using the OpenStudio command line interface (CLI), which\nwill create the empty OSM following the input simulation parameter\nspecifications.",
"type": null,
"default": null
},
{
"access": "None",
"name": "osm",
"description": "The file path to the empty OpenStudio Model (OSM) that has been generated\non this computer.",
"type": null,
"default": null
},
{
"access": "None",
"name": "idf",
"description": "The file path of the empty EnergyPlus Input Data File (IDF) that has been\ngenerated on this computer.",
"type": null,
"default": null
}
]
],
"inputs": [
{
"access": "item",
"name": "_epw_file",
"description": "Path to an .epw file on this computer as a text string.",
"type": "string",
"default": null
},
{
"access": "item",
"name": "_sim_par_",
"description": "A honeybee Energy SimulationParameter object that describes all\nof the setting for the simulation. If None, some default simulation\nparameters will automatically be used.",
"type": "System.Object",
"default": null
},
{
"access": "item",
"name": "_folder_",
"description": "An optional folder on this computer, into which the IDF and result\nfiles will be written.",
"type": "string",
"default": null
},
{
"access": "item",
"name": "_write",
"description": "Set to \"True\" to create the empty OSM file.",
"type": "bool",
"default": null
}
],
"subcategory": "5 :: Simulate",
"code": "\nimport sys\nimport os\nimport re\nimport json\n\ntry:\n from ladybug.futil import preparedir, nukedir\n from ladybug.epw import EPW\nexcept ImportError as e:\n raise ImportError('\\nFailed to import ladybug:\\n\\t{}'.format(e))\n\ntry:\n import honeybee.config as hb_config\nexcept ImportError as e:\n raise ImportError('\\nFailed to import honeybee:\\n\\t{}'.format(e))\n\ntry:\n from honeybee_energy.simulation.parameter import SimulationParameter\n from honeybee_energy.run import to_empty_osm_osw, run_osw\n from honeybee_energy.result.osw import OSW\nexcept ImportError as e:\n raise ImportError('\\nFailed to import honeybee_energy:\\n\\t{}'.format(e))\n\ntry:\n from lbt_recipes.version import check_openstudio_version\nexcept ImportError as e:\n raise ImportError('\\nFailed to import lbt_recipes:\\n\\t{}'.format(e))\n\ntry:\n from ladybug_{{cad}}.{{plugin}} import all_required_inputs, give_warning\nexcept ImportError as e:\n raise ImportError('\\nFailed to import ladybug_{{cad}}:\\n\\t{}'.format(e))\n\n\nif all_required_inputs(ghenv.Component) and _write:\n # check the presence of openstudio\n check_openstudio_version()\n\n # process the simulation parameters\n if _sim_par_ is None:\n _sim_par_ = SimulationParameter()\n _sim_par_.output.add_zone_energy_use()\n _sim_par_.output.add_hvac_energy_use()\n _sim_par_.output.add_electricity_generation()\n else:\n _sim_par_ = _sim_par_.duplicate() # ensure input is not edited\n\n # assign design days from the DDY next to the EPW if there are None\n if len(_sim_par_.sizing_parameter.design_days) == 0:\n msg = None\n folder, epw_file_name = os.path.split(_epw_file)\n ddy_file = os.path.join(folder, epw_file_name.replace('.epw', '.ddy'))\n if os.path.isfile(ddy_file):\n try:\n _sim_par_.sizing_parameter.add_from_ddy_996_004(ddy_file)\n except AssertionError:\n msg = 'No ddy_file_ was input into the _sim_par_ sizing ' \\\n 'parameters\\n and no design days were found in the .ddy file '\\\n 'next to the _epw_file.'\n else:\n msg = 'No ddy_file_ was input into the _sim_par_ sizing parameters\\n' \\\n 'and no .ddy file was found next to the _epw_file.'\n if msg is not None:\n epw_obj = EPW(_epw_file)\n des_days = [epw_obj.approximate_design_day('WinterDesignDay'),\n epw_obj.approximate_design_day('SummerDesignDay')]\n _sim_par_.sizing_parameter.design_days = des_days\n msg = msg + '\\nDesign days were generated from the input _epw_file but this ' \\\n '\\nis not as accurate as design days from DDYs distributed with the EPW.'\n give_warning(ghenv.Component, msg)\n print(msg)\n\n # process the simulation folder name and the directory\n _folder_ = hb_config.folders.default_simulation_folder if _folder_ is None else _folder_\n directory = os.path.join(_folder_, 'openstudio')\n\n # delete any existing files in the directory and prepare it for simulation\n nukedir(directory, True)\n preparedir(directory)\n\n # write the simulation parameter JSON\n sim_par_dict = _sim_par_.to_dict()\n sim_par_json = os.path.join(directory, 'simulation_parameter.json')\n if (sys.version_info < (3, 0)): # we need to manually encode it as UTF-8\n with open(sim_par_json, 'wb') as fp:\n sim_par_str = json.dumps(sim_par_dict, ensure_ascii=False)\n fp.write(sim_par_str.encode('utf-8'))\n else:\n with open(sim_par_json, 'w', encoding='utf-8') as fp:\n sim_par_str = json.dump(sim_par_dict, fp, ensure_ascii=False)\n\n # collect the two jsons for output and write out the osw file\n osw = to_empty_osm_osw(directory, sim_par_json, epw_file=_epw_file)\n\n # run the measure to translate the JSON\n osm, idf = run_osw(osw, silent=True)\n if idf is None: # measures failed to run correctly; parse out.osw\n log_osw = OSW(os.path.join(directory, 'out.osw'))\n errors = []\n for error, tb in zip(log_osw.errors, log_osw.error_tracebacks):\n if 'Cannot create a surface' in error:\n error = 'Your {{Cad}} Model units system is: {}. ' \\\n 'Is this correct?\\n{}'.format(units_system(), error)\n print(tb)\n errors.append(error)\n raise Exception('Failed to run OpenStudio CLI:\\n{}'.format('\\n'.join(errors)))\n",
"category": "HB-Energy",
"name": "HB Empty OSM",
"description": "Create an empty OpenStudio Model (OSM) file with no building geometry.\n_\nThis is useful as a starting point for OSMs to which detailed Ironbug systems\nwill be added. Such models with only Ironbug HVAC components can simulate\nin EnergyPlus if they use the LoadProfile:Plant object to represent the\nbuilding loads.\n_\nThey are useful for evaluating the performance of such heating/cooling plants\nand, by setting the simulation parameters and EPW file with this component, any\nsizing criteria for the plant components can be set.\n-"
}
156 changes: 156 additions & 0 deletions honeybee_grasshopper_energy/src/HB Empty OSM.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
# Honeybee: A Plugin for Environmental Analysis (GPL)
# This file is part of Honeybee.
#
# Copyright (c) 2024, Ladybug Tools.
# You should have received a copy of the GNU Affero General Public License
# along with Honeybee; If not, see <http://www.gnu.org/licenses/>.
#
# @license AGPL-3.0-or-later <https://spdx.org/licenses/AGPL-3.0-or-later>

"""
Create an empty OpenStudio Model (OSM) file with no building geometry.
_
This is useful as a starting point for OSMs to which detailed Ironbug systems
will be added. Such models with only Ironbug HVAC components can simulate
in EnergyPlus if they use the LoadProfile:Plant object to represent the
building loads.
_
They are useful for evaluating the performance of such heating/cooling plants
and, by setting the simulation parameters and EPW file with this component, any
sizing criteria for the plant components can be set.
-
Args:
_epw_file: Path to an .epw file on this computer as a text string.
_sim_par_: A honeybee Energy SimulationParameter object that describes all
of the setting for the simulation. If None, some default simulation
parameters will automatically be used.
_folder_: An optional folder on this computer, into which the IDF and result
files will be written.
_write: Set to "True" to create the empty OSM file.
Returns:
report: Reports, errors, warnings, etc.
osw: File path to the OpenStudio Workflow JSON on this machine. This workflow
is executed using the OpenStudio command line interface (CLI), which
will create the empty OSM following the input simulation parameter
specifications.
osm: The file path to the empty OpenStudio Model (OSM) that has been generated
on this computer.
idf: The file path of the empty EnergyPlus Input Data File (IDF) that has been
generated on this computer.
"""

ghenv.Component.Name = 'HB Empty OSM'
ghenv.Component.NickName = 'EmptyOSM'
ghenv.Component.Message = '1.8.0'
ghenv.Component.Category = 'HB-Energy'
ghenv.Component.SubCategory = '5 :: Simulate'
ghenv.Component.AdditionalHelpFromDocStrings = '0'

import sys
import os
import re
import json

try:
from ladybug.futil import preparedir, nukedir
from ladybug.epw import EPW
except ImportError as e:
raise ImportError('\nFailed to import ladybug:\n\t{}'.format(e))

try:
import honeybee.config as hb_config
except ImportError as e:
raise ImportError('\nFailed to import honeybee:\n\t{}'.format(e))

try:
from honeybee_energy.simulation.parameter import SimulationParameter
from honeybee_energy.run import to_empty_osm_osw, run_osw
from honeybee_energy.result.osw import OSW
except ImportError as e:
raise ImportError('\nFailed to import honeybee_energy:\n\t{}'.format(e))

try:
from lbt_recipes.version import check_openstudio_version
except ImportError as e:
raise ImportError('\nFailed to import lbt_recipes:\n\t{}'.format(e))

try:
from ladybug_rhino.grasshopper import all_required_inputs, give_warning
except ImportError as e:
raise ImportError('\nFailed to import ladybug_rhino:\n\t{}'.format(e))


if all_required_inputs(ghenv.Component) and _write:
# check the presence of openstudio
check_openstudio_version()

# process the simulation parameters
if _sim_par_ is None:
_sim_par_ = SimulationParameter()
_sim_par_.output.add_zone_energy_use()
_sim_par_.output.add_hvac_energy_use()
_sim_par_.output.add_electricity_generation()
else:
_sim_par_ = _sim_par_.duplicate() # ensure input is not edited

# assign design days from the DDY next to the EPW if there are None
if len(_sim_par_.sizing_parameter.design_days) == 0:
msg = None
folder, epw_file_name = os.path.split(_epw_file)
ddy_file = os.path.join(folder, epw_file_name.replace('.epw', '.ddy'))
if os.path.isfile(ddy_file):
try:
_sim_par_.sizing_parameter.add_from_ddy_996_004(ddy_file)
except AssertionError:
msg = 'No ddy_file_ was input into the _sim_par_ sizing ' \
'parameters\n and no design days were found in the .ddy file '\
'next to the _epw_file.'
else:
msg = 'No ddy_file_ was input into the _sim_par_ sizing parameters\n' \
'and no .ddy file was found next to the _epw_file.'
if msg is not None:
epw_obj = EPW(_epw_file)
des_days = [epw_obj.approximate_design_day('WinterDesignDay'),
epw_obj.approximate_design_day('SummerDesignDay')]
_sim_par_.sizing_parameter.design_days = des_days
msg = msg + '\nDesign days were generated from the input _epw_file but this ' \
'\nis not as accurate as design days from DDYs distributed with the EPW.'
give_warning(ghenv.Component, msg)
print(msg)

# process the simulation folder name and the directory
_folder_ = hb_config.folders.default_simulation_folder if _folder_ is None else _folder_
directory = os.path.join(_folder_, 'openstudio')

# delete any existing files in the directory and prepare it for simulation
nukedir(directory, True)
preparedir(directory)

# write the simulation parameter JSON
sim_par_dict = _sim_par_.to_dict()
sim_par_json = os.path.join(directory, 'simulation_parameter.json')
if (sys.version_info < (3, 0)): # we need to manually encode it as UTF-8
with open(sim_par_json, 'wb') as fp:
sim_par_str = json.dumps(sim_par_dict, ensure_ascii=False)
fp.write(sim_par_str.encode('utf-8'))
else:
with open(sim_par_json, 'w', encoding='utf-8') as fp:
sim_par_str = json.dump(sim_par_dict, fp, ensure_ascii=False)

# collect the two jsons for output and write out the osw file
osw = to_empty_osm_osw(directory, sim_par_json, epw_file=_epw_file)

# run the measure to translate the JSON
osm, idf = run_osw(osw, silent=True)
if idf is None: # measures failed to run correctly; parse out.osw
log_osw = OSW(os.path.join(directory, 'out.osw'))
errors = []
for error, tb in zip(log_osw.errors, log_osw.error_tracebacks):
if 'Cannot create a surface' in error:
error = 'Your Rhino Model units system is: {}. ' \
'Is this correct?\n{}'.format(units_system(), error)
print(tb)
errors.append(error)
raise Exception('Failed to run OpenStudio CLI:\n{}'.format('\n'.join(errors)))
Binary file not shown.

0 comments on commit ebd3423

Please sign in to comment.