openstudio-workflow 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,128 @@
1
+ ######################################################################
2
+ # Copyright (c) 2008-2014, Alliance for Sustainable Energy.
3
+ # All rights reserved.
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License as published by the Free Software Foundation; either
8
+ # version 2.1 of the License, or (at your option) any later version.
9
+ #
10
+ # This library is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ # Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public
16
+ # License along with this library; if not, write to the Free Software
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+ ######################################################################
19
+
20
+ class RunEnergyplus
21
+
22
+ # Initialize
23
+ # param directory: base directory where the simulation files are prepared
24
+ # param logger: logger object in which to write log messages
25
+ def initialize(directory, logger, adapter, options = {})
26
+
27
+ energyplus_path = nil
28
+ if /cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM
29
+ energyplus_path = 'C:/EnergyPlus-8-1-0'
30
+ else
31
+ energyplus_path ='/usr/local/EnergyPlus-8-1-0'
32
+ end
33
+
34
+ defaults = {
35
+ energyplus_path: energyplus_path
36
+ }
37
+ @options = defaults.merge(options)
38
+
39
+ # TODO: use openstudio tool finder for this
40
+ @directory = directory
41
+ @run_directory = "#{@directory}/run"
42
+ @adapter = adapter
43
+ @logger = logger
44
+ @results = {}
45
+
46
+ @logger.info "#{self.class} passed the following options #{@options}"
47
+ end
48
+
49
+ def perform
50
+ @logger.info "Calling #{__method__} in the #{self.class} class"
51
+ @logger.info "Current directory is #{@directory}"
52
+
53
+ # Ensure that the directory is created (but it should already be at this point)
54
+ FileUtils.mkdir_p(@run_directory)
55
+
56
+ # verify that the OSM, IDF, and the Weather files are in the run directory as the 'in.*' format
57
+ if @options[:run_openstudio][:weather_filename] && File.exist?(@options[:run_openstudio][:weather_filename])
58
+ # verify that it is named in.epw
59
+ unless File.basename(@options[:run_openstudio][:weather_filename]).downcase == 'in.idf'
60
+ FileUtils.copy(@options[:run_openstudio][:weather_filename], "#{@run_directory}/in.epw")
61
+ end
62
+ else
63
+ fail "EPW file not found or not sent to #{self.class}"
64
+ end
65
+
66
+ # Need to check the in.idf and in.osm
67
+ #FileUtils.copy(options[:osm], "#{@run_directory}/in.osm")
68
+ #FileUtils.copy(options[:idf], "#{@run_directory}/in.idf")
69
+
70
+ # can't create symlinks because the /vagrant mount is actually a windows mount
71
+ @logger.info "Copying EnergyPlus files to run directory: #{@run_directory}"
72
+ FileUtils.copy("#{@options[:energyplus_path]}/libbcvtb.so", "#{@run_directory}/libbcvtb.so")
73
+ FileUtils.copy("#{@options[:energyplus_path]}/libepexpat.so", "#{@run_directory}/libepexpat.so")
74
+ FileUtils.copy("#{@options[:energyplus_path]}/libepfmiimport.so", "#{@run_directory}/libepfmiimport.so")
75
+ FileUtils.copy("#{@options[:energyplus_path]}/libDElight.so", "#{@run_directory}/libDElight.so")
76
+ FileUtils.copy("#{@options[:energyplus_path]}/libDElight.so", "#{@run_directory}/libDElight.so")
77
+ FileUtils.copy("#{@options[:energyplus_path]}/ExpandObjects", "#{@run_directory}/ExpandObjects")
78
+ FileUtils.copy("#{@options[:energyplus_path]}/EnergyPlus", "#{@run_directory}/EnergyPlus")
79
+ FileUtils.copy("#{@options[:energyplus_path]}/Energy+.idd", "#{@run_directory}/Energy+.idd")
80
+
81
+ @results = call_energyplus
82
+
83
+ @results
84
+ end
85
+
86
+ private
87
+
88
+ def call_energyplus
89
+ begin
90
+ current_dir = Dir.pwd
91
+ Dir.chdir(@run_directory)
92
+ @logger.info "Starting simulation in run directory: #{Dir.pwd}"
93
+
94
+ File.open('stdout-expandobject', 'w') do |file|
95
+ IO.popen('ExpandObjects') do |io|
96
+ while (line = io.gets)
97
+ file << line
98
+ end
99
+ end
100
+ end
101
+
102
+ # Check if expand objects did anythying
103
+ if File.exist? 'expanded.idf'
104
+ FileUtils.mv('in.idf', 'pre-expand.idf', force: true) if File.exist?('in.idf')
105
+ FileUtils.mv('expanded.idf', 'in.idf', force: true)
106
+ end
107
+
108
+ # create stdout
109
+ File.open('stdout-energyplus', 'w') do |file|
110
+ IO.popen('EnergyPlus') do |io|
111
+ while (line = io.gets)
112
+ file << line
113
+ end
114
+ end
115
+ end
116
+
117
+ rescue Exception => e
118
+ log_message = "#{__FILE__} failed with #{e.message}, #{e.backtrace.join("\n")}"
119
+ @logger.error log_message
120
+ ensure
121
+ Dir.chdir(current_dir)
122
+ @logger.info 'EnergyPlus Completed'
123
+ end
124
+
125
+ # TODO: get list of all the files that are generated and return
126
+ {}
127
+ end
128
+ end
@@ -0,0 +1,218 @@
1
+ Output:Table:Monthly,
2
+ Building Energy Performance - Electricity, !- Name
3
+ 2, !- Digits After Decimal
4
+ InteriorLights:Electricity, !- Variable or Meter 1 Name
5
+ SumOrAverage, !- Aggregation Type for Variable or Meter 1
6
+ ExteriorLights:Electricity, !- Variable or Meter 2 Name
7
+ SumOrAverage, !- Aggregation Type for Variable or Meter 2
8
+ InteriorEquipment:Electricity, !- Variable or Meter 3 Name
9
+ SumOrAverage, !- Aggregation Type for Variable or Meter 3
10
+ ExteriorEquipment:Electricity, !- Variable or Meter 4 Name
11
+ SumOrAverage, !- Aggregation Type for Variable or Meter 4
12
+ Fans:Electricity, !- Variable or Meter 5 Name
13
+ SumOrAverage, !- Aggregation Type for Variable or Meter 5
14
+ Pumps:Electricity, !- Variable or Meter 6 Name
15
+ SumOrAverage, !- Aggregation Type for Variable or Meter 6
16
+ Heating:Electricity, !- Variable or Meter 7 Name
17
+ SumOrAverage, !- Aggregation Type for Variable or Meter 7
18
+ Cooling:Electricity, !- Variable or Meter 8 Name
19
+ SumOrAverage, !- Aggregation Type for Variable or Meter 8
20
+ HeatRejection:Electricity, !- Variable or Meter 9 Name
21
+ SumOrAverage, !- Aggregation Type for Variable or Meter 9
22
+ Humidifier:Electricity, !- Variable or Meter 10 Name
23
+ SumOrAverage, !- Aggregation Type for Variable or Meter 10
24
+ HeatRecovery:Electricity,!- Variable or Meter 11 Name
25
+ SumOrAverage, !- Aggregation Type for Variable or Meter 11
26
+ WaterSystems:Electricity,!- Variable or Meter 12 Name
27
+ SumOrAverage, !- Aggregation Type for Variable or Meter 12
28
+ Cogeneration:Electricity,!- Variable or Meter 13 Name
29
+ SumOrAverage, !- Aggregation Type for Variable or Meter 13
30
+ Refrigeration:Electricity,!- Variable or Meter 14 Name
31
+ SumOrAverage; !- Aggregation Type for Variable or Meter 14
32
+ Output:Table:Monthly,
33
+ Building Energy Performance - Natural Gas, !- Name
34
+ 2, !- Digits After Decimal
35
+ InteriorEquipment:Gas, !- Variable or Meter 1 Name
36
+ SumOrAverage, !- Aggregation Type for Variable or Meter 1
37
+ ExteriorEquipment:Gas, !- Variable or Meter 2 Name
38
+ SumOrAverage, !- Aggregation Type for Variable or Meter 2
39
+ Heating:Gas, !- Variable or Meter 3 Name
40
+ SumOrAverage, !- Aggregation Type for Variable or Meter 3
41
+ Cooling:Gas, !- Variable or Meter 4 Name
42
+ SumOrAverage, !- Aggregation Type for Variable or Meter 4
43
+ WaterSystems:Gas, !- Variable or Meter 5 Name
44
+ SumOrAverage, !- Aggregation Type for Variable or Meter 5
45
+ Cogeneration:Gas, !- Variable or Meter 6 Name
46
+ SumOrAverage; !- Aggregation Type for Variable or Meter 6
47
+ Output:Table:Monthly,
48
+ Building Energy Performance - District Heating, !- Name
49
+ 2, !- Digits After Decimal
50
+ InteriorLights:DistrictHeating, !- Variable or Meter 1 Name
51
+ SumOrAverage, !- Aggregation Type for Variable or Meter 1
52
+ ExteriorLights:DistrictHeating, !- Variable or Meter 2 Name
53
+ SumOrAverage, !- Aggregation Type for Variable or Meter 2
54
+ InteriorEquipment:DistrictHeating, !- Variable or Meter 3 Name
55
+ SumOrAverage, !- Aggregation Type for Variable or Meter 3
56
+ ExteriorEquipment:DistrictHeating, !- Variable or Meter 4 Name
57
+ SumOrAverage, !- Aggregation Type for Variable or Meter 4
58
+ Fans:DistrictHeating, !- Variable or Meter 5 Name
59
+ SumOrAverage, !- Aggregation Type for Variable or Meter 5
60
+ Pumps:DistrictHeating, !- Variable or Meter 6 Name
61
+ SumOrAverage, !- Aggregation Type for Variable or Meter 6
62
+ Heating:DistrictHeating, !- Variable or Meter 7 Name
63
+ SumOrAverage, !- Aggregation Type for Variable or Meter 7
64
+ Cooling:DistrictHeating, !- Variable or Meter 8 Name
65
+ SumOrAverage, !- Aggregation Type for Variable or Meter 8
66
+ HeatRejection:DistrictHeating, !- Variable or Meter 9 Name
67
+ SumOrAverage, !- Aggregation Type for Variable or Meter 9
68
+ Humidifier:DistrictHeating, !- Variable or Meter 10 Name
69
+ SumOrAverage, !- Aggregation Type for Variable or Meter 10
70
+ HeatRecovery:DistrictHeating,!- Variable or Meter 11 Name
71
+ SumOrAverage, !- Aggregation Type for Variable or Meter 11
72
+ WaterSystems:DistrictHeating,!- Variable or Meter 12 Name
73
+ SumOrAverage, !- Aggregation Type for Variable or Meter 12
74
+ Cogeneration:DistrictHeating,!- Variable or Meter 13 Name
75
+ SumOrAverage; !- Aggregation Type for Variable or Meter 13
76
+ Output:Table:Monthly,
77
+ Building Energy Performance - District Cooling, !- Name
78
+ 2, !- Digits After Decimal
79
+ InteriorLights:DistrictCooling, !- Variable or Meter 1 Name
80
+ SumOrAverage, !- Aggregation Type for Variable or Meter 1
81
+ ExteriorLights:DistrictCooling, !- Variable or Meter 2 Name
82
+ SumOrAverage, !- Aggregation Type for Variable or Meter 2
83
+ InteriorEquipment:DistrictCooling, !- Variable or Meter 3 Name
84
+ SumOrAverage, !- Aggregation Type for Variable or Meter 3
85
+ ExteriorEquipment:DistrictCooling, !- Variable or Meter 4 Name
86
+ SumOrAverage, !- Aggregation Type for Variable or Meter 4
87
+ Fans:DistrictCooling, !- Variable or Meter 5 Name
88
+ SumOrAverage, !- Aggregation Type for Variable or Meter 5
89
+ Pumps:DistrictCooling, !- Variable or Meter 6 Name
90
+ SumOrAverage, !- Aggregation Type for Variable or Meter 6
91
+ Heating:DistrictCooling, !- Variable or Meter 7 Name
92
+ SumOrAverage, !- Aggregation Type for Variable or Meter 7
93
+ Cooling:DistrictCooling, !- Variable or Meter 8 Name
94
+ SumOrAverage, !- Aggregation Type for Variable or Meter 8
95
+ HeatRejection:DistrictCooling, !- Variable or Meter 9 Name
96
+ SumOrAverage, !- Aggregation Type for Variable or Meter 9
97
+ Humidifier:DistrictCooling, !- Variable or Meter 10 Name
98
+ SumOrAverage, !- Aggregation Type for Variable or Meter 10
99
+ HeatRecovery:DistrictCooling,!- Variable or Meter 11 Name
100
+ SumOrAverage, !- Aggregation Type for Variable or Meter 11
101
+ WaterSystems:DistrictCooling,!- Variable or Meter 12 Name
102
+ SumOrAverage, !- Aggregation Type for Variable or Meter 12
103
+ Cogeneration:DistrictCooling,!- Variable or Meter 13 Name
104
+ SumOrAverage; !- Aggregation Type for Variable or Meter 13
105
+ Output:Table:Monthly,
106
+ Building Energy Performance - Electricity Peak Demand, !- Name
107
+ 2, !- Digits After Decimal
108
+ Electricity:Facility, !- Variable or Meter 1 Name
109
+ Maximum, !- Aggregation Type for Variable or Meter 1
110
+ InteriorLights:Electricity, !- Variable or Meter 1 Name
111
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 1
112
+ ExteriorLights:Electricity, !- Variable or Meter 2 Name
113
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 2
114
+ InteriorEquipment:Electricity, !- Variable or Meter 3 Name
115
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 3
116
+ ExteriorEquipment:Electricity, !- Variable or Meter 4 Name
117
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 4
118
+ Fans:Electricity, !- Variable or Meter 5 Name
119
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 5
120
+ Pumps:Electricity, !- Variable or Meter 6 Name
121
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 6
122
+ Heating:Electricity, !- Variable or Meter 7 Name
123
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 7
124
+ Cooling:Electricity, !- Variable or Meter 8 Name
125
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 8
126
+ HeatRejection:Electricity, !- Variable or Meter 9 Name
127
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 9
128
+ Humidifier:Electricity, !- Variable or Meter 10 Name
129
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 10
130
+ HeatRecovery:Electricity,!- Variable or Meter 11 Name
131
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 11
132
+ WaterSystems:Electricity,!- Variable or Meter 12 Name
133
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 12
134
+ Cogeneration:Electricity,!- Variable or Meter 13 Name
135
+ ValueWhenMaximumOrMinimum; !- Aggregation Type for Variable or Meter 13
136
+ Output:Table:Monthly,
137
+ Building Energy Performance - Natural Gas Peak Demand, !- Name
138
+ 2, !- Digits After Decimal
139
+ Gas:Facility, !- Variable or Meter 1 Name
140
+ Maximum, !- Aggregation Type for Variable or Meter 1
141
+ InteriorEquipment:Gas, !- Variable or Meter 1 Name
142
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 1
143
+ ExteriorEquipment:Gas, !- Variable or Meter 2 Name
144
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 2
145
+ Heating:Gas, !- Variable or Meter 3 Name
146
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 3
147
+ Cooling:Gas, !- Variable or Meter 4 Name
148
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 4
149
+ WaterSystems:Gas, !- Variable or Meter 5 Name
150
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 5
151
+ Cogeneration:Gas, !- Variable or Meter 6 Name
152
+ ValueWhenMaximumOrMinimum; !- Aggregation Type for Variable or Meter 6
153
+ Output:Table:Monthly,
154
+ Building Energy Performance - District Heating Peak Demand, !- Name
155
+ 2, !- Digits After Decimal
156
+ DistrictHeating:Facility, !- Variable or Meter 1 Name
157
+ Maximum, !- Aggregation Type for Variable or Meter 1
158
+ InteriorLights:DistrictHeating, !- Variable or Meter 1 Name
159
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 1
160
+ ExteriorLights:DistrictHeating, !- Variable or Meter 2 Name
161
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 2
162
+ InteriorEquipment:DistrictHeating, !- Variable or Meter 3 Name
163
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 3
164
+ ExteriorEquipment:DistrictHeating, !- Variable or Meter 4 Name
165
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 4
166
+ Fans:DistrictHeating, !- Variable or Meter 5 Name
167
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 5
168
+ Pumps:DistrictHeating, !- Variable or Meter 6 Name
169
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 6
170
+ Heating:DistrictHeating, !- Variable or Meter 7 Name
171
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 7
172
+ Cooling:DistrictHeating, !- Variable or Meter 8 Name
173
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 8
174
+ HeatRejection:DistrictHeating, !- Variable or Meter 9 Name
175
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 9
176
+ Humidifier:DistrictHeating, !- Variable or Meter 10 Name
177
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 10
178
+ HeatRecovery:DistrictHeating,!- Variable or Meter 11 Name
179
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 11
180
+ WaterSystems:DistrictHeating,!- Variable or Meter 12 Name
181
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 12
182
+ Cogeneration:DistrictHeating,!- Variable or Meter 13 Name
183
+ ValueWhenMaximumOrMinimum; !- Aggregation Type for Variable or Meter 13
184
+ Output:Table:Monthly,
185
+ Building Energy Performance - District Cooling Peak Demand, !- Name
186
+ 2, !- Digits After Decimal
187
+ DistrictCooling:Facility, !- Variable or Meter 1 Name
188
+ Maximum, !- Aggregation Type for Variable or Meter 1
189
+ InteriorLights:DistrictCooling, !- Variable or Meter 1 Name
190
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 1
191
+ ExteriorLights:DistrictCooling, !- Variable or Meter 2 Name
192
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 2
193
+ InteriorEquipment:DistrictCooling, !- Variable or Meter 3 Name
194
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 3
195
+ ExteriorEquipment:DistrictCooling, !- Variable or Meter 4 Name
196
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 4
197
+ Fans:DistrictCooling, !- Variable or Meter 5 Name
198
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 5
199
+ Pumps:DistrictCooling, !- Variable or Meter 6 Name
200
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 6
201
+ Heating:DistrictCooling, !- Variable or Meter 7 Name
202
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 7
203
+ Cooling:DistrictCooling, !- Variable or Meter 8 Name
204
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 8
205
+ HeatRejection:DistrictCooling, !- Variable or Meter 9 Name
206
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 9
207
+ Humidifier:DistrictCooling, !- Variable or Meter 10 Name
208
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 10
209
+ HeatRecovery:DistrictCooling,!- Variable or Meter 11 Name
210
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 11
211
+ WaterSystems:DistrictCooling,!- Variable or Meter 12 Name
212
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 12
213
+ Cogeneration:DistrictCooling,!- Variable or Meter 13 Name
214
+ ValueWhenMaximumOrMinimum; !- Aggregation Type for Variable or Meter 13
215
+ Output:Meter,Electricity:Facility,Timestep; !- [J]
216
+ Output:Meter,Gas:Facility,Timestep; !- [J]
217
+ Output:Meter,DistrictCooling:Facility,Timestep; !- [J]
218
+ Output:Meter,DistrictHeating:Facility,Timestep; !- [J]
@@ -0,0 +1,344 @@
1
+ ######################################################################
2
+ # Copyright (c) 2008-2014, Alliance for Sustainable Energy.
3
+ # All rights reserved.
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License as published by the Free Software Foundation; either
8
+ # version 2.1 of the License, or (at your option) any later version.
9
+ #
10
+ # This library is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ # Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public
16
+ # License along with this library; if not, write to the Free Software
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+ ######################################################################
19
+
20
+ # TODO: I hear that measures can step on each other if not run in their own directory
21
+ class RunOpenstudio
22
+ CRASH_ON_NO_WORKFLOW_VARIABLE = false
23
+
24
+ # Initialize
25
+ # param directory: base directory where the simulation files are prepared
26
+ # param logger: logger object in which to write log messages
27
+ def initialize(directory, logger, adapter, options = {})
28
+ defaults = {format: 'hash', use_monthly_reports: false, analysis_root_path: '.'}
29
+ @options = defaults.merge(options)
30
+ @directory = directory
31
+ # TODO: there is a base number of arguments that each job will need including @run_directory. abstract it out.
32
+ @run_directory = "#{@directory}/run"
33
+ @adapter = adapter
34
+ @results = {}
35
+ @logger = logger
36
+ @logger.info "#{self.class} passed the following options #{@options}"
37
+
38
+ # initialize instance variables that are needed in the perform section
39
+ @model = nil
40
+ @model_idf = nil
41
+ @analysis_json = nil
42
+ # TODO: rename datapoint_json to just datapoint
43
+ @datapoint_json = nil
44
+ @output_attributes = {}
45
+ @report_measures = []
46
+ @measure_type_lookup = {
47
+ :openstudio_measure => 'RubyMeasure',
48
+ :energyplus_measure => 'EnergyPlusMeasure',
49
+ :reporting_measure => 'ReportingMeasure'
50
+ }
51
+ end
52
+
53
+ def perform
54
+ @logger.info "Calling #{__method__} in the #{self.class} class"
55
+ @logger.info "Current directory is #{@directory}"
56
+
57
+ @logger.info "Retrieving datapoint and problem"
58
+ @datapoint_json = @adapter.get_datapoint(@directory, @options)
59
+ @analysis_json = @adapter.get_problem(@directory, @options)
60
+
61
+ if @analysis_json && @analysis_json[:analysis]
62
+ @model = load_seed_model
63
+ load_weather_file
64
+
65
+ apply_measures(:openstudio_measure)
66
+
67
+ translate_to_energyplus
68
+
69
+ apply_measures(:energyplus_measure)
70
+
71
+ @logger.info "Measure output attributes JSON is #{@output_attributes}"
72
+ File.open("#{@run_directory}/measure_attributes.json", 'w') {
73
+ |f| f << JSON.pretty_generate(@output_attributes)
74
+ }
75
+ end
76
+
77
+ save_osm_and_idf
78
+
79
+ @results
80
+ end
81
+
82
+ private
83
+
84
+ def save_osm_and_idf
85
+ # save the data
86
+ a = Time.now
87
+ osm_filename = "#{@run_directory}/out_raw.osm"
88
+ File.open(osm_filename, 'w') { |f| f << @model.to_s }
89
+ b = Time.now
90
+ @logger.info "Ruby write took #{b.to_f - a.to_f}"
91
+
92
+ a = Time.now
93
+ osm_filename = "#{@run_directory}/in.osm"
94
+ @model.save(OpenStudio::Path.new(osm_filename), true)
95
+ b = Time.now
96
+ @logger.info "OpenStudio write took #{b.to_f - a.to_f}"
97
+
98
+ # Run EnergyPlus using run energyplus script
99
+ idf_filename = "#{@run_directory}/in.idf"
100
+ File.open(idf_filename, 'w') { |f| f << @model_idf.to_s }
101
+
102
+ # TODO: convert this to an OpenStudio method instead of substituting the data as text
103
+ if @options[:use_monthly_reports]
104
+ @logger.info 'Adding monthly reports to EnergyPlus IDF'
105
+ to_append = File.read(File.join(File.dirname(__FILE__), 'monthly_report.idf'))
106
+ File.open(idf_filename, 'a') do |handle|
107
+ handle.puts to_append
108
+ end
109
+ end
110
+
111
+ @results[:osm] = File.expand_path(osm_filename)
112
+ @results[:idf] = File.expand_path(idf_filename)
113
+ end
114
+
115
+ def load_seed_model
116
+ model = nil
117
+ @logger.info 'Loading seed model'
118
+
119
+ baseline_model_path = nil
120
+ # Unique case to use the previous generated OSM as the seed
121
+ if @options[:run_xml] && @options[:run_xml][:osm_filename]
122
+ if File.exist? @options[:run_xml][:osm_filename]
123
+ baseline_model_path = @options[:run_xml][:osm_filename]
124
+ end
125
+ elsif @analysis_json[:analysis][:seed]
126
+ @logger.info "Seed model is #{@analysis_json[:analysis][:seed]}"
127
+ if @analysis_json[:analysis][:seed][:path]
128
+
129
+ # assume that the seed model has been placed in the directory
130
+ baseline_model_path = File.expand_path(
131
+ File.join(@options[:analysis_root_path], @analysis_json[:analysis][:seed][:path]))
132
+ else
133
+ fail 'No seed model path in JSON defined'
134
+ end
135
+ else
136
+ fail 'No seed model block'
137
+ end
138
+
139
+ if baseline_model_path
140
+ if File.exist? baseline_model_path
141
+ @logger.info "Reading in baseline model #{baseline_model_path}"
142
+ translator = OpenStudio::OSVersion::VersionTranslator.new
143
+ model = translator.loadModel(baseline_model_path)
144
+ fail 'OpenStudio model is empty or could not be loaded' if model.empty?
145
+ model = model.get
146
+ else
147
+ fail "Seed model '#{baseline_model_path}' did not exist"
148
+ end
149
+ else
150
+ fail "No baseline/seed model found"
151
+ end
152
+
153
+ model
154
+ end
155
+
156
+ # Save the weather file to the instance variable
157
+ def load_weather_file
158
+ weather_filename = nil
159
+ if @options[:run_xml] && @options[:run_xml][:weather_filename]
160
+ if File.exist? @options[:run_xml][:weather_filename]
161
+ weather_filename = @options[:run_xml][:weather_filename]
162
+ end
163
+ elsif @analysis_json[:analysis][:weather_file]
164
+ if @analysis_json[:analysis][:weather_file][:path]
165
+ weather_filename = File.expand_path(
166
+ File.join(@options[:analysis_root_path], @analysis_json[:analysis][:weather_file][:path]))
167
+ else
168
+ fail 'No weather file path defined'
169
+ end
170
+ else
171
+ fail 'No weather file block defined'
172
+ end
173
+
174
+ unless File.exist?(weather_filename)
175
+ fail "Could not find weather file for simulation #{weather_filename}"
176
+ end
177
+
178
+ @results[:weather_filename] = weather_filename
179
+
180
+ weather_filename
181
+ end
182
+
183
+ # Forward translate to energyplus
184
+ def translate_to_energyplus
185
+ if @model_idf.nil?
186
+ @logger.info 'Translate object to EnergyPlus IDF in Prep for EnergyPlus Measure'
187
+ a = Time.now
188
+ # ensure objects exist for reporting purposes
189
+ @model.getFacility
190
+ @model.getBuilding
191
+ forward_translator = OpenStudio::EnergyPlus::ForwardTranslator.new
192
+ @model_idf = forward_translator.translateModel(@model)
193
+ b = Time.now
194
+ @logger.info "Translate object to energyplus IDF took #{b.to_f - a.to_f}"
195
+ end
196
+ end
197
+
198
+ def apply_arguments(argument_map, argument)
199
+ success = true
200
+
201
+ if argument[:value]
202
+ @logger.info "Setting argument value #{argument[:name]} to #{argument[:value]}"
203
+
204
+ v = argument_map[argument[:name]]
205
+ fail 'Could not find argument map in measure' unless v
206
+ value_set = v.setValue(argument[:value])
207
+ fail "Could not set argument #{argument[:name]} of value #{argument[:value]} on model" unless value_set
208
+ argument_map[argument[:name]] = v.clone
209
+ else
210
+ fail "Value for argument '#{argument[:name]}' not set in argument list" if CRASH_ON_NO_WORKFLOW_VARIABLE
211
+ @logger.warn "Value for argument '#{argument[:name]}' not set in argument list therefore will use default"
212
+ #success = false
213
+
214
+ # TODO: what is the fail case (success = false?)
215
+ end
216
+
217
+ success
218
+ end
219
+
220
+ # Apply the variable values to the measure argument map object
221
+ def apply_variables(argument_map, variable)
222
+ success = true
223
+
224
+ # save the uuid of the variable
225
+ variable_uuid = variable[:uuid].to_sym
226
+ if variable[:argument]
227
+ variable_name = variable[:argument][:name]
228
+
229
+ # Get the value from the data point json that was set via R / Problem Formulation
230
+ if @datapoint_json[:data_point]
231
+ if @datapoint_json[:data_point][:set_variable_values]
232
+ if @datapoint_json[:data_point][:set_variable_values][variable_uuid]
233
+ @logger.info "Setting variable '#{variable_name}' to #{@datapoint_json[:data_point][:set_variable_values][variable_uuid]}"
234
+ v = argument_map[variable_name]
235
+ fail 'Could not find argument map in measure' unless v
236
+ variable_value = @datapoint_json[:data_point][:set_variable_values][variable_uuid]
237
+ value_set = v.setValue(variable_value)
238
+ fail "Could not set variable '#{variable_name}' of value #{variable_value} on model" unless value_set
239
+ argument_map[variable_name] = v.clone
240
+ else
241
+ fail "[ERROR] Value for variable '#{variable_name}:#{variable_uuid}' not set in datapoint object" if CRASH_ON_NO_WORKFLOW_VARIABLE
242
+ @logger.warn "Value for variable '#{variable_name}:#{variable_uuid}' not set in datapoint object"
243
+ # success = false
244
+ end
245
+ else
246
+ fail 'No block for set_variable_values in data point record'
247
+ end
248
+ else
249
+ fail 'No block for data_point in data_point record'
250
+ end
251
+ else
252
+ fail "Variable '#{variable_name}' is defined but no argument is present"
253
+ end
254
+
255
+ success
256
+ end
257
+
258
+ def apply_measure(workflow_item)
259
+ measure_path = workflow_item[:measure_definition_directory]
260
+ measure_name = workflow_item[:measure_definition_class_name]
261
+
262
+ @logger.info "Loading measure in relative path #{measure_path}"
263
+ measure_file_path = File.expand_path(
264
+ File.join(@options[:analysis_root_path], measure_path, 'measure.rb'))
265
+ fail "Measure file does not exist #{measure_name} in #{measure_file_path}" unless File.exist? measure_file_path
266
+
267
+ require measure_file_path
268
+ measure = Object.const_get(measure_name).new
269
+ runner = OpenStudio::Ruleset::OSRunner.new
270
+ result = nil
271
+
272
+ arguments = measure.arguments(@model)
273
+
274
+ # Create argument map and initialize all the arguments
275
+ argument_map = OpenStudio::Ruleset::OSArgumentMap.new
276
+ arguments.each do |v|
277
+ argument_map[v.name] = v.clone
278
+ end
279
+
280
+ @logger.info "Iterating over arguments for workflow item '#{workflow_item[:name]}'"
281
+ if workflow_item[:arguments]
282
+ workflow_item[:arguments].each do |argument|
283
+ success = apply_arguments(argument_map, argument)
284
+ fail "could not set arguments" unless success
285
+ end
286
+ end
287
+
288
+ @logger.info "Iterating over variables for workflow item '#{workflow_item[:name]}'"
289
+ if workflow_item[:variables]
290
+ workflow_item[:variables].each do |variable|
291
+ success = apply_variables(argument_map, variable)
292
+ fail "could not set variables" unless success
293
+ end
294
+ end
295
+
296
+ begin
297
+ if workflow_item[:measure_type] == 'RubyMeasure'
298
+ @logger.info "Running runner for '#{workflow_item[:name]}'"
299
+ measure.run(@model, runner, argument_map)
300
+ @logger.info "Finished runner for '#{workflow_item[:name]}'"
301
+ elsif workflow_item[:measure_type] == 'EnergyPlusMeasure'
302
+ measure.run(@model_idf, runner, argument_map)
303
+ elsif workflow_item[:measure_type] == 'ReportingMeasure'
304
+ report_measures << measure
305
+ end
306
+ rescue Exception => e
307
+ log_message = "Runner error #{__FILE__} failed with #{e.message}, #{e.backtrace.join("\n")}"
308
+ fail log_message
309
+ end
310
+
311
+ begin
312
+ result = runner.result
313
+
314
+ @logger.info result.initialCondition.get.logMessage unless result.initialCondition.empty?
315
+ @logger.info result.finalCondition.get.logMessage unless result.finalCondition.empty?
316
+
317
+ result.warnings.each { |w| @logger.info w.logMessage }
318
+ result.errors.each { |w| @logger.info w.logMessage }
319
+ result.info.each { |w| @logger.info w.logMessage }
320
+ rescue Exception => e
321
+ log_message = "Runner error #{__FILE__} failed with #{e.message}, #{e.backtrace.join("\n")}"
322
+ fail log_message
323
+ end
324
+
325
+ begin
326
+ measure_attributes = JSON.parse(OpenStudio::toJSON(result.attributes), symbolize_names: true)
327
+ @output_attributes[workflow_item[:name].to_sym] = measure_attributes[:attributes]
328
+ rescue Exception => e
329
+ log_message = "TODO: #{__FILE__} failed with #{e.message}, #{e.backtrace.join("\n")}"
330
+ @logger.warn log_message
331
+ end
332
+ end
333
+
334
+ def apply_measures(measure_type)
335
+ if @analysis_json[:analysis][:problem] && @analysis_json[:analysis][:problem][:workflow]
336
+ @logger.info "Applying measures for #{@measure_type_lookup[measure_type]}"
337
+ @analysis_json[:analysis][:problem][:workflow].each do |wf|
338
+ next unless wf[:measure_type] == @measure_type_lookup[measure_type]
339
+
340
+ apply_measure(wf)
341
+ end
342
+ end
343
+ end
344
+ end