diff --git a/honeybee_grasshopper_energy/icon/HB Empty OSM.png b/honeybee_grasshopper_energy/icon/HB Empty OSM.png new file mode 100644 index 0000000..5972045 Binary files /dev/null and b/honeybee_grasshopper_energy/icon/HB Empty OSM.png differ diff --git a/honeybee_grasshopper_energy/json/HB_Empty_OSM.json b/honeybee_grasshopper_energy/json/HB_Empty_OSM.json new file mode 100644 index 0000000..71ee344 --- /dev/null +++ b/honeybee_grasshopper_energy/json/HB_Empty_OSM.json @@ -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-" +} \ No newline at end of file diff --git a/honeybee_grasshopper_energy/src/HB Empty OSM.py b/honeybee_grasshopper_energy/src/HB Empty OSM.py new file mode 100644 index 0000000..020217d --- /dev/null +++ b/honeybee_grasshopper_energy/src/HB Empty OSM.py @@ -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 . +# +# @license 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))) diff --git a/honeybee_grasshopper_energy/user_objects/HB Empty OSM.ghuser b/honeybee_grasshopper_energy/user_objects/HB Empty OSM.ghuser new file mode 100644 index 0000000..ca546b8 Binary files /dev/null and b/honeybee_grasshopper_energy/user_objects/HB Empty OSM.ghuser differ