-
Notifications
You must be signed in to change notification settings - Fork 15
Wrap PythonPlugin:SearchPaths #214
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
0cf2fd8
Add dummy py script with import from plugin script.
joseph-robertson a6e4771
Add commented osm test in model_tests.
joseph-robertson dc5b206
Put back the python_plugin_program.py
jmarrec 7f2fee3
Clarify how/for which tests .py script files are used
jmarrec 96a35a5
Add a python version, make the python_plugin use a program name that'…
jmarrec 7d5f06e
Replace with an actual Path
jmarrec 8ce3479
Merge branch 'develop' into python-plugin-search-paths
joseph-robertson 3550785
Merge branch 'develop' into python-plugin-search-paths
joseph-robertson ea03dbb
Merge branch 'develop' into python-plugin-search-paths
joseph-robertson f479574
Merge branch 'develop' into python-plugin-search-paths
jmarrec 9682d66
Ignore python_plugin_search_paths_script.py
jmarrec 042548b
Merge branch 'python-plugin-search-paths' of github.com:NREL/OpenStud…
joseph-robertson 3a9d440
Merge branch 'develop' into python-plugin-search-paths
joseph-robertson f0a6873
Update test_helpers.rb
jmarrec File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| # This file is used by python_plugin.osm | ||
| from pyenergyplus.plugin import EnergyPlusPlugin | ||
|
|
||
|
|
||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,132 @@ | ||
| import tempfile | ||
| from pathlib import Path | ||
|
|
||
| import openstudio | ||
|
|
||
| from lib.baseline_model import BaselineModel | ||
|
|
||
| model = BaselineModel() | ||
|
|
||
| # make a 1 story, 100m X 50m, 5 zone core/perimeter building | ||
| model.add_geometry(length=100, width=50, num_floors=1, floor_to_floor_height=4, plenum_height=0, perimeter_zone_depth=3) | ||
|
|
||
| # assign constructions from a local library to the walls/windows/etc. in the model | ||
| model.set_constructions() | ||
|
|
||
| # set whole building space type; simplified 90.1-2004 Large Office Whole Building | ||
| model.set_space_type() | ||
|
|
||
| # add design days to the model (Chicago) | ||
| model.add_design_days() | ||
|
|
||
| zone_names = sorted([x.nameString() for x in model.getThermalZones()]) | ||
|
|
||
| zone_names_str_list = '["' + '", "'.join(zone_names) + '"]' | ||
|
|
||
| # Add a PythonPlugin:Variable (all OS SDK PythonPluginVariable objects are | ||
| # translated to a single E+ PythonPlugin:Variables (extensible object)) | ||
| py_var = openstudio.model.PythonPluginVariable(model) | ||
| py_var.setName("AverageBuildingTemp") | ||
|
|
||
| # Add a PythonPlugin:OutputVariable for that variable | ||
| py_out_var = openstudio.model.PythonPluginOutputVariable(py_var) | ||
| py_out_var.setName("Averaged Building Temperature") | ||
| py_out_var.setTypeofDatainVariable("Averaged") | ||
| py_out_var.setUpdateFrequency("ZoneTimestep") | ||
| py_out_var.setUnits("C") | ||
|
|
||
| # Add a regular Output:Variable that references it | ||
| out_var = openstudio.model.OutputVariable("PythonPlugin:OutputVariable", model) | ||
| out_var.setKeyValue(py_out_var.nameString()) | ||
| out_var.setReportingFrequency("Timestep") | ||
|
|
||
| # Add output variables for Zone Mean Air Temperature, so we can compare | ||
| outputVariable = openstudio.model.OutputVariable("Zone Mean Air Temperature", model) | ||
| outputVariable.setReportingFrequency("Timestep") | ||
|
|
||
| # Trend Variable: while this is a fully functioning object, you're probably | ||
| # best just using a storage variable on the Python side (eg: a list) | ||
| py_trend_var = openstudio.model.PythonPluginTrendVariable(py_var) | ||
| py_trend_var.setName("Running Averaged Building Temperature") | ||
| n_timesteps = 24 * model.getTimestep().numberOfTimestepsPerHour() | ||
| py_trend_var.setNumberofTimestepstobeLogged(n_timesteps) | ||
|
|
||
| py_var2 = openstudio.model.PythonPluginVariable(model) | ||
| py_var2.setName("RunningAverageBuildingTemp") | ||
|
|
||
| py_out_trend_var = openstudio.model.PythonPluginOutputVariable(py_var2) | ||
| py_out_trend_var.setName("Running Averaged Building Temperature") | ||
| py_out_trend_var.setTypeofDatainVariable("Averaged") | ||
| py_out_trend_var.setUpdateFrequency("ZoneTimestep") | ||
| py_out_trend_var.setUnits("C") | ||
|
|
||
| out_trend_var = openstudio.model.OutputVariable("PythonPlugin:OutputVariable", model) | ||
| out_trend_var.setReportingFrequency("Timestep") | ||
|
|
||
| pluginClassName = "AverageZoneTemps" | ||
|
|
||
| python_plugin_file_content = f"""from pyenergyplus.plugin import EnergyPlusPlugin | ||
| # NOTE: This external script must be locatable, so we'll add it to the PythonPluginSearchPaths | ||
| import python_plugin_search_paths_script | ||
|
|
||
|
|
||
| class {pluginClassName}(EnergyPlusPlugin): | ||
|
|
||
| def __init__(self): | ||
| super().__init__() | ||
| self.do_setup = True | ||
|
|
||
| def on_end_of_zone_timestep_before_zone_reporting(self, state) -> int: | ||
| if self.do_setup: | ||
| self.data['zone_volumes'] = [] | ||
| self.data['zone_temps'] = [] | ||
| zone_names = {zone_names_str_list} | ||
| for zone_name in zone_names: | ||
| handle = self.api.exchange.get_internal_variable_handle(state, 'Zone Air Volume', zone_name) | ||
| zone_volume = self.api.exchange.get_internal_variable_value(state, handle) | ||
| self.data['zone_volumes'].append(zone_volume) | ||
| self.data['zone_temps'].append( | ||
| self.api.exchange.get_variable_handle(state, 'Zone Mean Air Temperature', zone_name) | ||
| ) | ||
| self.data['avg_temp_variable'] = self.api.exchange.get_global_handle(state, '{py_var.nameString()}') | ||
| self.data['trend'] = self.api.exchange.get_trend_handle(state, '{py_trend_var.nameString()}') | ||
| self.data['running_avg_temp_variable'] = self.api.exchange.get_global_handle(state, '{py_var2.nameString()}') | ||
| self.do_setup = False | ||
| zone_temps = list() | ||
| for t_handle in self.data['zone_temps']: | ||
| zone_temps.append(self.api.exchange.get_variable_value(state, t_handle)) | ||
| numerator = 0.0 | ||
| denominator = 0.0 | ||
| for i in range(len(self.data['zone_volumes'])): | ||
| numerator += self.data['zone_volumes'][i] * zone_temps[i] | ||
| denominator += self.data['zone_volumes'][i] | ||
| average_temp = numerator / denominator | ||
| self.api.exchange.set_global_value(state, self.data['avg_temp_variable'], average_temp) | ||
|
|
||
| past_daily_avg_temp = self.api.exchange.get_trend_average(state, self.data['trend'], {n_timesteps}) | ||
| self.api.exchange.set_global_value(state, self.data['running_avg_temp_variable'], past_daily_avg_temp) | ||
| return 0 | ||
| """ | ||
|
|
||
| # Write it to a temporary directory so we don't pollute the current directory | ||
| # ExternalFile will copy it | ||
| pluginPath = Path(tempfile.gettempdir()) / f"{Path(__file__).stem}_program.py" | ||
| pluginPath.write_text(python_plugin_file_content) | ||
|
|
||
| # create the external file object | ||
| external_file = openstudio.model.ExternalFile.getExternalFile(model, str(pluginPath)) | ||
| external_file = external_file.get() | ||
|
|
||
| # create the python plugin instance object | ||
| python_plugin_instance = openstudio.model.PythonPluginInstance(external_file, pluginClassName) | ||
| python_plugin_instance.setRunDuringWarmupDays(False) | ||
|
|
||
| # create the python plugin search paths object (this test should fail without it) | ||
| python_plugin_search_paths = model.getPythonPluginSearchPaths() | ||
| python_plugin_search_paths.setAddCurrentWorkingDirectorytoSearchPath(True) | ||
| python_plugin_search_paths.setAddInputFileDirectorytoSearchPath(True) | ||
| python_plugin_search_paths.setAddepinEnvironmentVariabletoSearchPath(True) | ||
| python_plugin_search_paths.addSearchPath(Path(__file__).parent) | ||
|
|
||
| # save the OpenStudio model (.osm) | ||
| model.save_openstudio_osm(osm_save_directory=None, osm_name="in.osm") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,137 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| require 'openstudio' | ||
| require_relative 'lib/baseline_model' | ||
| require 'tmpdir' | ||
|
|
||
| model = BaselineModel.new | ||
|
|
||
| # make a 1 story, 100m X 50m, 5 zone core/perimeter building | ||
| model.add_geometry({ 'length' => 100, | ||
| 'width' => 50, | ||
| 'num_floors' => 1, | ||
| 'floor_to_floor_height' => 4, | ||
| 'plenum_height' => 0, | ||
| 'perimeter_zone_depth' => 3 }) | ||
|
|
||
| # assign constructions from a local library to the walls/windows/etc. in the model | ||
| model.set_constructions | ||
|
|
||
| # set whole building space type; simplified 90.1-2004 Large Office Whole Building | ||
| model.set_space_type | ||
|
|
||
| # add design days to the model (Chicago) | ||
| model.add_design_days | ||
|
|
||
| zone_names = model.getThermalZones.map(&:nameString).sort | ||
|
|
||
| zone_names_str_list = '["' + zone_names.join('", "') + '"]' | ||
|
|
||
| # Add a PythonPlugin:Variable (all OS SDK PythonPluginVariable objects are | ||
| # translated to a single E+ PythonPlugin:Variables (extensible object)) | ||
| py_var = OpenStudio::Model::PythonPluginVariable.new(model) | ||
| py_var.setName('AverageBuildingTemp') | ||
|
|
||
| # Add a PythonPlugin:OutputVariable for that variable | ||
| py_out_var = OpenStudio::Model::PythonPluginOutputVariable.new(py_var) | ||
| py_out_var.setName('Averaged Building Temperature') | ||
| py_out_var.setTypeofDatainVariable('Averaged') | ||
| py_out_var.setUpdateFrequency('ZoneTimestep') | ||
| py_out_var.setUnits('C') | ||
|
|
||
| # Add a regular Output:Variable that references it | ||
| out_var = OpenStudio::Model::OutputVariable.new('PythonPlugin:OutputVariable', model) | ||
| out_var.setKeyValue(py_out_var.nameString) | ||
| out_var.setReportingFrequency('Timestep') | ||
|
|
||
| # Add output variables for Zone Mean Air Temperature, so we can compare | ||
| outputVariable = OpenStudio::Model::OutputVariable.new('Zone Mean Air Temperature', model) | ||
| outputVariable.setReportingFrequency('Timestep') | ||
|
|
||
| # Trend Variable: while this is a fully functioning object, you're probably | ||
| # best just using a storage variable on the Python side (eg: a list) | ||
| py_trend_var = OpenStudio::Model::PythonPluginTrendVariable.new(py_var) | ||
| py_trend_var.setName('Running Averaged Building Temperature') | ||
| n_timesteps = 24 * model.getTimestep.numberOfTimestepsPerHour | ||
| py_trend_var.setNumberofTimestepstobeLogged(n_timesteps) | ||
|
|
||
| py_var2 = OpenStudio::Model::PythonPluginVariable.new(model) | ||
| py_var2.setName('RunningAverageBuildingTemp') | ||
|
|
||
| py_out_trend_var = OpenStudio::Model::PythonPluginOutputVariable.new(py_var2) | ||
| py_out_trend_var.setName('Running Averaged Building Temperature') | ||
| py_out_trend_var.setTypeofDatainVariable('Averaged') | ||
| py_out_trend_var.setUpdateFrequency('ZoneTimestep') | ||
| py_out_trend_var.setUnits('C') | ||
|
|
||
| out_trend_var = OpenStudio::Model::OutputVariable.new('PythonPlugin:OutputVariable', model) | ||
| out_trend_var.setReportingFrequency('Timestep') | ||
|
|
||
| pluginClassName = 'AverageZoneTemps' | ||
|
|
||
| python_plugin_file_content = ''"from pyenergyplus.plugin import EnergyPlusPlugin | ||
| # NOTE: This external script must be locatable, so we'll add it to the PythonPluginSearchPaths | ||
| import python_plugin_search_paths_script | ||
|
|
||
|
|
||
| class #{pluginClassName}(EnergyPlusPlugin): | ||
|
|
||
| def __init__(self): | ||
| super().__init__() | ||
| self.do_setup = True | ||
|
|
||
| def on_end_of_zone_timestep_before_zone_reporting(self, state) -> int: | ||
| if self.do_setup: | ||
| self.data['zone_volumes'] = [] | ||
| self.data['zone_temps'] = [] | ||
| zone_names = #{zone_names_str_list} | ||
| for zone_name in zone_names: | ||
| handle = self.api.exchange.get_internal_variable_handle(state, 'Zone Air Volume', zone_name) | ||
| zone_volume = self.api.exchange.get_internal_variable_value(state, handle) | ||
| self.data['zone_volumes'].append(zone_volume) | ||
| self.data['zone_temps'].append( | ||
| self.api.exchange.get_variable_handle(state, 'Zone Mean Air Temperature', zone_name) | ||
| ) | ||
| self.data['avg_temp_variable'] = self.api.exchange.get_global_handle(state, '#{py_var.nameString}') | ||
| self.data['trend'] = self.api.exchange.get_trend_handle(state, '#{py_trend_var.nameString}') | ||
| self.data['running_avg_temp_variable'] = self.api.exchange.get_global_handle(state, '#{py_var2.nameString}') | ||
| self.do_setup = False | ||
| zone_temps = list() | ||
| for t_handle in self.data['zone_temps']: | ||
| zone_temps.append(self.api.exchange.get_variable_value(state, t_handle)) | ||
| numerator = 0.0 | ||
| denominator = 0.0 | ||
| for i in range(len(self.data['zone_volumes'])): | ||
| numerator += self.data['zone_volumes'][i] * zone_temps[i] | ||
| denominator += self.data['zone_volumes'][i] | ||
| average_temp = numerator / denominator | ||
| self.api.exchange.set_global_value(state, self.data['avg_temp_variable'], average_temp) | ||
|
|
||
| past_daily_avg_temp = self.api.exchange.get_trend_average(state, self.data['trend'], #{n_timesteps}) | ||
| self.api.exchange.set_global_value(state, self.data['running_avg_temp_variable'], past_daily_avg_temp) | ||
| return 0 | ||
| "'' | ||
|
|
||
| # Write it to a temporary directory so we don't pollute the current directory | ||
| # ExternalFile will copy it | ||
| stem = File.basename(__FILE__, File.extname(__FILE__)) | ||
| pluginPath = File.join(Dir.tmpdir, "#{stem}_program.py") | ||
| File.write(pluginPath, python_plugin_file_content) | ||
|
|
||
| # create the external file object | ||
| external_file = OpenStudio::Model::ExternalFile.getExternalFile(model, pluginPath) | ||
| external_file = external_file.get | ||
|
|
||
| # create the python plugin instance object | ||
| python_plugin_instance = OpenStudio::Model::PythonPluginInstance.new(external_file, pluginClassName) | ||
| python_plugin_instance.setRunDuringWarmupDays(false) | ||
|
|
||
| # create the python plugin search paths object (this test should fail without it) | ||
| python_plugin_search_paths = model.getPythonPluginSearchPaths | ||
| python_plugin_search_paths.setAddCurrentWorkingDirectorytoSearchPath(true) | ||
| python_plugin_search_paths.setAddInputFileDirectorytoSearchPath(true) | ||
| python_plugin_search_paths.setAddepinEnvironmentVariabletoSearchPath(true) | ||
| python_plugin_search_paths.addSearchPath(File.dirname(__FILE__)) | ||
|
Comment on lines
+129
to
+134
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you confirm this fails without this object please? |
||
|
|
||
| # save the OpenStudio model (.osm) | ||
| model.save_openstudio_osm({ 'osm_save_directory' => Dir.pwd, 'osm_name' => 'in.osm' }) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| # This file is used by python_plugin_search_paths | ||
| print('hello world') |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dynamic #{stem_program.py}