Skip to content

Commit

Permalink
fix(simulate): Add a better error message when the input is not a Model
Browse files Browse the repository at this point in the history
  • Loading branch information
chriswmackey authored and Chris Mackey committed Mar 18, 2024
1 parent 8160af5 commit 9d96dcd
Show file tree
Hide file tree
Showing 4 changed files with 6 additions and 3 deletions.
Binary file modified honeybee_grasshopper_energy/icon/HB Model to OSM.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions honeybee_grasshopper_energy/json/HB_Model_to_OSM.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "1.7.3",
"version": "1.7.4",
"nickname": "ModelToOSM",
"outputs": [
[
Expand Down Expand Up @@ -120,7 +120,7 @@
}
],
"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_openstudio_osw, run_osw, run_idf, \\\n output_energyplus_files\n from honeybee_energy.result.err import Err\n from honeybee_energy.result.osw import OSW\n from honeybee_energy.config import folders as energy_folders\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\n from ladybug_{{cad}}.config import units_system\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 and check that the version is compatible\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 clean_name = re.sub(r'[^.A-Za-z0-9_-]', '_', _model.display_name)\n directory = os.path.join(_folder_, clean_name, 'openstudio')\n\n # duplicate model to avoid mutating it as we edit it for energy simulation\n _model = _model.duplicate()\n # scale the model if the units are not meters\n if _model.units != 'Meters':\n _model.convert_to_units('Meters')\n # remove degenerate geometry within native E+ tolerance of 0.01 meters\n try:\n _model.remove_degenerate_geometry(0.01)\n except ValueError:\n error = 'Failed to remove degenerate Rooms.\\nYour Model units system is: {}. ' \\\n 'Is this correct?'.format(units_system())\n raise ValueError(error)\n # remove the HVAC from any Rooms lacking setpoints\n rem_msgs = _model.properties.energy.remove_hvac_from_no_setpoints()\n if rem_msgs is not None and len(rem_msgs) != 0:\n msg = '\\n'.join(rem_msgs)\n give_warning(ghenv.Component, msg)\n print(msg)\n\n # auto-assign stories if there are none since most OpenStudio measures need these\n if len(_model.stories) == 0 and len(_model.rooms) != 0:\n _model.assign_stories_by_floor_height()\n\n # delete any existing files in the directory and prepare it for simulation\n nukedir(directory, True)\n preparedir(directory)\n sch_directory = os.path.join(directory, 'schedules')\n preparedir(sch_directory)\n\n # write the model parameter JSONs\n model_dict = _model.to_dict(triangulate_sub_faces=True)\n _model.properties.energy.add_autocal_properties_to_dict(model_dict)\n model_json = os.path.join(directory, '{}.hbjson'.format(clean_name))\n if (sys.version_info < (3, 0)): # we need to manually encode it as UTF-8\n with open(model_json, 'wb') as fp:\n model_str = json.dumps(model_dict, ensure_ascii=False)\n fp.write(model_str.encode('utf-8'))\n else:\n with open(model_json, 'w', encoding='utf-8') as fp:\n model_str = json.dump(model_dict, fp, ensure_ascii=False)\n\n # write the simulation parameter JSONs\n sim_par_dict = _sim_par_.to_dict()\n sim_par_json = os.path.join(directory, 'simulation_parameter.json')\n with open(sim_par_json, 'w') as fp:\n json.dump(sim_par_dict, fp)\n\n # process any measures input to the component\n measures = None if len(measures_) == 0 or measures_[0] is None else measures_\n no_report_meas = True if measures is None else \\\n all(meas.type != 'ReportingMeasure' for meas in measures)\n str_inject = None if no_report_meas or add_str_ == [] or add_str_[0] is None \\\n else '\\n'.join(add_str_)\n\n # collect the two jsons for output and write out the osw file\n jsons = [model_json, sim_par_json]\n osw = to_openstudio_osw(\n directory, model_json, sim_par_json, additional_measures=measures,\n epw_file=_epw_file, schedule_directory=sch_directory,\n strings_to_inject=str_inject)\n\n # run the measure to translate the model JSON to an openstudio measure\n silent = True if run_ == 3 else False\n if run_ > 0 and not no_report_meas: # everything must run with OS CLI\n if run_ == 1: # simulate everything at once\n osm, idf = run_osw(osw, measures_only=False, silent=silent)\n sql, zsz, rdd, html, err = output_energyplus_files(os.path.dirname(idf))\n else: # remove reporting measure and give a warning\n m_to_remove = [m.identifier for m in measures if m.type == 'ReportingMeasure']\n with open(osw, 'r') as op:\n osw_data = json.load(op)\n s_to_remove = []\n for i, step in enumerate(osw_data['steps']):\n if step['measure_dir_name'] in m_to_remove:\n s_to_remove.append(i)\n for i in reversed(s_to_remove):\n osw_data['steps'].pop(i)\n with open(osw, 'wb') as fp:\n workflow_str = json.dumps(osw_data, indent=4, ensure_ascii=False)\n fp.write(workflow_str.encode('utf-8'))\n msg = 'The following were reporting measures and were not\\n' \\\n 'included in the OSW to avoid running the simulation:\\n{}'.format(\n '\\n'.join(m_to_remove))\n give_warning(ghenv.Component, msg)\n print(msg)\n osm, idf = run_osw(osw, silent=silent)\n elif run_ > 0: # no reporting measure; simulate separately from measure application\n osm, idf = run_osw(osw, silent=silent)\n # process the additional strings\n if len(add_str_) != 0 and add_str_[0] is not None and idf is not None:\n add_str = '\\n'.join(add_str_)\n with open(idf, \"a\") as idf_file:\n idf_file.write(add_str)\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 elif run_ in (1, 3): # run the resulting idf throught EnergyPlus\n sql, zsz, rdd, html, err = run_idf(idf, _epw_file, silent=silent)\n\n # parse the error log and report any warnings\n if run_ in (1, 3) and err is not None:\n err_obj = Err(err)\n print(err_obj.file_contents)\n for warn in err_obj.severe_errors:\n give_warning(ghenv.Component, warn)\n for error in err_obj.fatal_errors:\n raise Exception(error)\n",
"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\n from honeybee.model import Model\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_openstudio_osw, run_osw, run_idf, \\\n output_energyplus_files\n from honeybee_energy.result.err import Err\n from honeybee_energy.result.osw import OSW\n from honeybee_energy.config import folders as energy_folders\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\n from ladybug_{{cad}}.config import units_system\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 and check that the version is compatible\n check_openstudio_version()\n assert isinstance(_model, Model), \\\n 'Expected Honeybee Model for _model input. Got {}.'.format(type(_model))\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 clean_name = re.sub(r'[^.A-Za-z0-9_-]', '_', _model.display_name)\n directory = os.path.join(_folder_, clean_name, 'openstudio')\n\n # duplicate model to avoid mutating it as we edit it for energy simulation\n _model = _model.duplicate()\n # scale the model if the units are not meters\n if _model.units != 'Meters':\n _model.convert_to_units('Meters')\n # remove degenerate geometry within native E+ tolerance of 0.01 meters\n try:\n _model.remove_degenerate_geometry(0.01)\n except ValueError:\n error = 'Failed to remove degenerate Rooms.\\nYour Model units system is: {}. ' \\\n 'Is this correct?'.format(units_system())\n raise ValueError(error)\n # remove the HVAC from any Rooms lacking setpoints\n rem_msgs = _model.properties.energy.remove_hvac_from_no_setpoints()\n if rem_msgs is not None and len(rem_msgs) != 0:\n msg = '\\n'.join(rem_msgs)\n give_warning(ghenv.Component, msg)\n print(msg)\n\n # auto-assign stories if there are none since most OpenStudio measures need these\n if len(_model.stories) == 0 and len(_model.rooms) != 0:\n _model.assign_stories_by_floor_height()\n\n # delete any existing files in the directory and prepare it for simulation\n nukedir(directory, True)\n preparedir(directory)\n sch_directory = os.path.join(directory, 'schedules')\n preparedir(sch_directory)\n\n # write the model parameter JSONs\n model_dict = _model.to_dict(triangulate_sub_faces=True)\n _model.properties.energy.add_autocal_properties_to_dict(model_dict)\n model_json = os.path.join(directory, '{}.hbjson'.format(clean_name))\n if (sys.version_info < (3, 0)): # we need to manually encode it as UTF-8\n with open(model_json, 'wb') as fp:\n model_str = json.dumps(model_dict, ensure_ascii=False)\n fp.write(model_str.encode('utf-8'))\n else:\n with open(model_json, 'w', encoding='utf-8') as fp:\n model_str = json.dump(model_dict, fp, ensure_ascii=False)\n\n # write the simulation parameter JSONs\n sim_par_dict = _sim_par_.to_dict()\n sim_par_json = os.path.join(directory, 'simulation_parameter.json')\n with open(sim_par_json, 'w') as fp:\n json.dump(sim_par_dict, fp)\n\n # process any measures input to the component\n measures = None if len(measures_) == 0 or measures_[0] is None else measures_\n no_report_meas = True if measures is None else \\\n all(meas.type != 'ReportingMeasure' for meas in measures)\n str_inject = None if no_report_meas or add_str_ == [] or add_str_[0] is None \\\n else '\\n'.join(add_str_)\n\n # collect the two jsons for output and write out the osw file\n jsons = [model_json, sim_par_json]\n osw = to_openstudio_osw(\n directory, model_json, sim_par_json, additional_measures=measures,\n epw_file=_epw_file, schedule_directory=sch_directory,\n strings_to_inject=str_inject)\n\n # run the measure to translate the model JSON to an openstudio measure\n silent = True if run_ == 3 else False\n if run_ > 0 and not no_report_meas: # everything must run with OS CLI\n if run_ == 1: # simulate everything at once\n osm, idf = run_osw(osw, measures_only=False, silent=silent)\n sql, zsz, rdd, html, err = output_energyplus_files(os.path.dirname(idf))\n else: # remove reporting measure and give a warning\n m_to_remove = [m.identifier for m in measures if m.type == 'ReportingMeasure']\n with open(osw, 'r') as op:\n osw_data = json.load(op)\n s_to_remove = []\n for i, step in enumerate(osw_data['steps']):\n if step['measure_dir_name'] in m_to_remove:\n s_to_remove.append(i)\n for i in reversed(s_to_remove):\n osw_data['steps'].pop(i)\n with open(osw, 'wb') as fp:\n workflow_str = json.dumps(osw_data, indent=4, ensure_ascii=False)\n fp.write(workflow_str.encode('utf-8'))\n msg = 'The following were reporting measures and were not\\n' \\\n 'included in the OSW to avoid running the simulation:\\n{}'.format(\n '\\n'.join(m_to_remove))\n give_warning(ghenv.Component, msg)\n print(msg)\n osm, idf = run_osw(osw, silent=silent)\n elif run_ > 0: # no reporting measure; simulate separately from measure application\n osm, idf = run_osw(osw, silent=silent)\n # process the additional strings\n if len(add_str_) != 0 and add_str_[0] is not None and idf is not None:\n add_str = '\\n'.join(add_str_)\n with open(idf, \"a\") as idf_file:\n idf_file.write(add_str)\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 elif run_ in (1, 3): # run the resulting idf throught EnergyPlus\n sql, zsz, rdd, html, err = run_idf(idf, _epw_file, silent=silent)\n\n # parse the error log and report any warnings\n if run_ in (1, 3) and err is not None:\n err_obj = Err(err)\n print(err_obj.file_contents)\n for warn in err_obj.severe_errors:\n give_warning(ghenv.Component, warn)\n for error in err_obj.fatal_errors:\n raise Exception(error)\n",
"category": "HB-Energy",
"name": "HB Model to OSM",
"description": "Write a honeybee Model to an OSM file (OpenStudio Model), which can then be translated\nto an IDF file and then run through EnergyPlus.\n-"
Expand Down
5 changes: 4 additions & 1 deletion honeybee_grasshopper_energy/src/HB Model to OSM.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@

ghenv.Component.Name = 'HB Model to OSM'
ghenv.Component.NickName = 'ModelToOSM'
ghenv.Component.Message = '1.7.3'
ghenv.Component.Message = '1.7.4'
ghenv.Component.Category = 'HB-Energy'
ghenv.Component.SubCategory = '5 :: Simulate'
ghenv.Component.AdditionalHelpFromDocStrings = '1'
Expand All @@ -92,6 +92,7 @@

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

Expand Down Expand Up @@ -120,6 +121,8 @@
if all_required_inputs(ghenv.Component) and _write:
# check the presence of openstudio and check that the version is compatible
check_openstudio_version()
assert isinstance(_model, Model), \
'Expected Honeybee Model for _model input. Got {}.'.format(type(_model))

# process the simulation parameters
if _sim_par_ is None:
Expand Down
Binary file modified honeybee_grasshopper_energy/user_objects/HB Model to OSM.ghuser
Binary file not shown.

0 comments on commit 9d96dcd

Please sign in to comment.