From 941e6efb9aaa48f05b36313ec48db0d1b4570976 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Tue, 20 Dec 2022 09:51:57 -0700 Subject: [PATCH 1/6] Add second plugin test for pointing to erb py template. --- model/simulationtests/python_plugin_2.rb | 96 ++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 model/simulationtests/python_plugin_2.rb diff --git a/model/simulationtests/python_plugin_2.rb b/model/simulationtests/python_plugin_2.rb new file mode 100644 index 000000000..7ec8839da --- /dev/null +++ b/model/simulationtests/python_plugin_2.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + +require 'openstudio' +require_relative 'lib/baseline_model' +require 'tmpdir' +require 'erb' + +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 + +# 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' + +# get the python plugin program (erb template) +pluginTemplatePath = File.join(File.dirname(__FILE__), 'lib/python_plugin_program.py') +in_py = '' +File.open(pluginTemplatePath, 'r') do |file| + in_py = file.read +end + +# configure template with variable values +renderer = ERB.new(in_py) +out_py = renderer.result(binding) + +# Write it to a temporary directory so we don't pollute the current directory +# ExternalFile will copy it +pluginPath = File.join(Dir.tmpdir, 'python_plugin_program.py') +File.open(pluginPath, 'w') do |file| + file << out_py +end + +# 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) + +# save the OpenStudio model (.osm) +model.save_openstudio_osm({ 'osm_save_directory' => Dir.pwd, 'osm_name' => 'in.osm' }) From 9c9a107f728fb952d54cc05372328c3fc6f2155e Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Tue, 20 Dec 2022 09:52:11 -0700 Subject: [PATCH 2/6] Call new test from model_tests file. --- model_tests.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/model_tests.rb b/model_tests.rb index 899d98bd7..84fd017fd 100644 --- a/model_tests.rb +++ b/model_tests.rb @@ -928,6 +928,15 @@ def test_python_plugin_rb # result = sim_test('python_plugin.osm') # end + def test_python_plugin_2_rb + result = sim_test('python_plugin_2.rb') + end + + # TODO: To be added in the next official release after: 3.5.0 + # def test_python_plugin_2_osm + # result = sim_test('python_plugin_2.osm') + # end + def test_refrigeration_system_rb result = sim_test('refrigeration_system.rb') end From 716e3a028c633ffbe217435b4baffee62f163d07 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Tue, 20 Dec 2022 10:59:22 -0700 Subject: [PATCH 3/6] Comment. --- model/simulationtests/python_plugin_2.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/model/simulationtests/python_plugin_2.rb b/model/simulationtests/python_plugin_2.rb index 7ec8839da..4bc847697 100644 --- a/model/simulationtests/python_plugin_2.rb +++ b/model/simulationtests/python_plugin_2.rb @@ -73,7 +73,7 @@ in_py = file.read end -# configure template with variable values +# configure plugin template with variable values renderer = ERB.new(in_py) out_py = renderer.result(binding) From b7329e70cee4be60a4995a5d25ee803211402be7 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Tue, 20 Dec 2022 11:15:06 -0700 Subject: [PATCH 4/6] Add template python plugin program. --- .../lib/python_plugin_program.py | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 model/simulationtests/lib/python_plugin_program.py diff --git a/model/simulationtests/lib/python_plugin_program.py b/model/simulationtests/lib/python_plugin_program.py new file mode 100644 index 000000000..4da95e007 --- /dev/null +++ b/model/simulationtests/lib/python_plugin_program.py @@ -0,0 +1,38 @@ +from pyenergyplus.plugin import EnergyPlusPlugin + +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 = <%= model.getThermalZones.map(&:nameString).sort %> + 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'], 96) + self.api.exchange.set_global_value(state, self.data['running_avg_temp_variable'], past_daily_avg_temp) + return 0 From b47fb79c80c5c6abe218315f7373a18bcecdad44 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 25 Jan 2023 13:00:19 -0700 Subject: [PATCH 5/6] Try out importing non standard library. --- model/simulationtests/lib/python_plugin_program.csv | 2 ++ model/simulationtests/lib/python_plugin_program.py | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 model/simulationtests/lib/python_plugin_program.csv diff --git a/model/simulationtests/lib/python_plugin_program.csv b/model/simulationtests/lib/python_plugin_program.csv new file mode 100644 index 000000000..00aecc5b7 --- /dev/null +++ b/model/simulationtests/lib/python_plugin_program.csv @@ -0,0 +1,2 @@ +numerator,denominator +0,0 diff --git a/model/simulationtests/lib/python_plugin_program.py b/model/simulationtests/lib/python_plugin_program.py index 4da95e007..060226deb 100644 --- a/model/simulationtests/lib/python_plugin_program.py +++ b/model/simulationtests/lib/python_plugin_program.py @@ -1,11 +1,17 @@ from pyenergyplus.plugin import EnergyPlusPlugin +import os, sys +sys.path.append('C:/Python38/Lib/site-packages') # this should (needs to?) be same version as E+'s version +import pandas as pd + class <%= pluginClassName %>(EnergyPlusPlugin): def __init__(self): super().__init__() self.do_setup = True + self.df = pd.read_csv('C:/OpenStudio/OpenStudio-resources/model/simulationtests/lib/python_plugin_program.csv') + def on_end_of_zone_timestep_before_zone_reporting(self, state) -> int: if self.do_setup: self.data['zone_volumes'] = [] @@ -25,8 +31,8 @@ def on_end_of_zone_timestep_before_zone_reporting(self, state) -> int: 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 + numerator = float(self.df.iloc[0]['numerator']) + denominator = float(self.df.iloc[0]['denominator']) for i in range(len(self.data['zone_volumes'])): numerator += self.data['zone_volumes'][i] * zone_temps[i] denominator += self.data['zone_volumes'][i] From 5e3d33953f030c86a7c4610803cce5a82cccf277 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Fri, 7 Apr 2023 10:20:57 -0700 Subject: [PATCH 6/6] External file on csv to avoid abs path in plugin file. --- model/simulationtests/lib/python_plugin_program.py | 2 +- model/simulationtests/python_plugin_2.rb | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/model/simulationtests/lib/python_plugin_program.py b/model/simulationtests/lib/python_plugin_program.py index 060226deb..65e4a9b4c 100644 --- a/model/simulationtests/lib/python_plugin_program.py +++ b/model/simulationtests/lib/python_plugin_program.py @@ -10,7 +10,7 @@ def __init__(self): super().__init__() self.do_setup = True - self.df = pd.read_csv('C:/OpenStudio/OpenStudio-resources/model/simulationtests/lib/python_plugin_program.csv') + self.df = pd.read_csv(os.path.join(os.path.dirname(__file__), 'python_plugin_program.csv')) def on_end_of_zone_timestep_before_zone_reporting(self, state) -> int: if self.do_setup: diff --git a/model/simulationtests/python_plugin_2.rb b/model/simulationtests/python_plugin_2.rb index 4bc847697..1a21a03d8 100644 --- a/model/simulationtests/python_plugin_2.rb +++ b/model/simulationtests/python_plugin_2.rb @@ -73,6 +73,9 @@ in_py = file.read end +dataPath = File.join(File.dirname(__FILE__), 'lib/python_plugin_program.csv') +OpenStudio::Model::ExternalFile.getExternalFile(model, dataPath) + # configure plugin template with variable values renderer = ERB.new(in_py) out_py = renderer.result(binding)