openstudio-workflow 1.0.0.pat1 → 1.0.0

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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/README.md +16 -68
  4. data/Rakefile +9 -9
  5. data/bin/openstudio_cli +786 -0
  6. data/lib/openstudio/workflow/adapters/input/local.rb +97 -0
  7. data/lib/openstudio/workflow/adapters/output/local.rb +90 -0
  8. data/lib/openstudio/workflow/adapters/output/socket.rb +70 -0
  9. data/lib/openstudio/workflow/{jobs/run_preflight/run_preflight.rb → adapters/output/web.rb} +37 -19
  10. data/lib/openstudio/workflow/{adapter.rb → adapters/output_adapter.rb} +53 -51
  11. data/lib/openstudio/workflow/job.rb +22 -0
  12. data/lib/openstudio/workflow/jobs/{run_energyplus → resources}/monthly_report.idf +0 -0
  13. data/lib/openstudio/workflow/jobs/run_energyplus.rb +49 -0
  14. data/lib/openstudio/workflow/jobs/run_ep_measures.rb +55 -0
  15. data/lib/openstudio/workflow/jobs/run_initialization.rb +136 -0
  16. data/lib/openstudio/workflow/jobs/run_os_measures.rb +59 -0
  17. data/lib/openstudio/workflow/jobs/run_postprocess.rb +53 -0
  18. data/lib/openstudio/workflow/jobs/run_preprocess.rb +81 -0
  19. data/lib/openstudio/workflow/jobs/run_reporting_measures.rb +86 -0
  20. data/lib/openstudio/workflow/jobs/run_translation.rb +49 -0
  21. data/lib/openstudio/workflow/multi_delegator.rb +1 -3
  22. data/lib/openstudio/workflow/registry.rb +137 -0
  23. data/lib/openstudio/workflow/run.rb +182 -221
  24. data/lib/openstudio/workflow/time_logger.rb +1 -1
  25. data/lib/openstudio/workflow/util/energyplus.rb +564 -0
  26. data/lib/openstudio/workflow/util/io.rb +33 -0
  27. data/lib/openstudio/workflow/util/measure.rb +520 -0
  28. data/lib/openstudio/workflow/util/model.rb +100 -0
  29. data/lib/openstudio/workflow/util/post_process.rb +177 -0
  30. data/lib/openstudio/workflow/util/weather_file.rb +108 -0
  31. data/lib/openstudio/workflow/util.rb +14 -0
  32. data/lib/openstudio/workflow/version.rb +1 -1
  33. data/lib/openstudio/workflow_json.rb +399 -0
  34. data/lib/openstudio/workflow_runner.rb +213 -0
  35. data/lib/openstudio-workflow.rb +13 -118
  36. metadata +45 -85
  37. data/lib/openstudio/extended_runner.rb +0 -105
  38. data/lib/openstudio/workflow/adapters/local.rb +0 -101
  39. data/lib/openstudio/workflow/adapters/mongo.rb +0 -227
  40. data/lib/openstudio/workflow/jobs/lib/apply_measures.rb +0 -253
  41. data/lib/openstudio/workflow/jobs/run_energyplus/run_energyplus.rb +0 -314
  42. data/lib/openstudio/workflow/jobs/run_openstudio/run_openstudio.rb +0 -230
  43. data/lib/openstudio/workflow/jobs/run_postprocess/run_postprocess.rb +0 -110
  44. data/lib/openstudio/workflow/jobs/run_reporting_measures/run_reporting_measures.rb +0 -471
  45. data/lib/openstudio/workflow/jobs/run_runmanager/run_runmanager.rb +0 -247
  46. data/lib/openstudio/workflow/jobs/run_xml/run_xml.rb +0 -279
@@ -1,314 +0,0 @@
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
- ENERGYPLUS_REGEX = /^energyplus\D{0,4}$/i
22
- EXPAND_OBJECTS_REGEX = /^expandobjects\D{0,4}$/i
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, time_logger, adapter, workflow_arguments, past_results, options = {})
28
- @logger = logger
29
-
30
- energyplus_path = find_energyplus
31
- defaults = {
32
- energyplus_path: energyplus_path
33
- }
34
- @options = defaults.merge(options)
35
-
36
- # TODO: use openstudio tool finder for this
37
- @directory = directory
38
- @run_directory = "#{@directory}/run"
39
- @adapter = adapter
40
- @time_logger = time_logger
41
- @workflow_arguments = workflow_arguments
42
- @past_results = past_results
43
- @results = {}
44
-
45
- # container for storing the energyplus files there were copied into the local directory. These will be
46
- # removed at the end of the simulation.
47
- @energyplus_files = []
48
- @energyplus_exe = nil
49
- @expand_objects_exe = nil
50
-
51
- @logger.info "#{self.class} passed the following options #{@options}"
52
- end
53
-
54
- def perform
55
- @logger.info "Calling #{__method__} in the #{self.class} class"
56
- @logger.info "Current directory is #{@directory}"
57
-
58
- # Ensure that the directory is created (but it should already be at this point)
59
- FileUtils.mkdir_p(@run_directory)
60
-
61
- # if the weather file is already in the directory, then just use that weather file
62
- weather_file_name = nil
63
- weather_files = Dir["#{@directory}/*.epw"]
64
- if weather_files.size > 1
65
- @logger.info 'Multiple weather files in the directory. Will rely on the weather file name in the openstudio model'
66
- elsif weather_files.size == 1
67
- weather_file_name = weather_files.first
68
- end
69
-
70
- # verify that the OSM, IDF, and the Weather files are in the run directory as the 'in.*' format
71
- if !weather_file_name &&
72
- @options[:run_openstudio] &&
73
- @options[:run_openstudio][:weather_filename] &&
74
- File.exist?(@options[:run_openstudio][:weather_filename])
75
- weather_file_name = @options[:run_openstudio][:weather_filename]
76
- end
77
-
78
- if weather_file_name
79
- # verify that it is named in.epw
80
- @logger.info "Weather file for EnergyPlus simulation is #{weather_file_name}"
81
- FileUtils.copy(weather_file_name, "#{@run_directory}/in.epw")
82
- else
83
- fail "EPW file not found or not sent to #{self.class}"
84
- end
85
-
86
- # check if the run folder has an IDF. If not then check if the parent folder does.
87
- idf_file_name = nil
88
- if File.exist?("#{@run_directory}/in.idf")
89
- @logger.info 'IDF (in.idf) already exists in the run directory'
90
- else
91
- # glob for idf at the directory level
92
- idfs = Dir["#{@directory}/*.idf"]
93
- if idfs.size > 1
94
- @logger.info 'Multiple IDF files in the directory. Cannot continue'
95
- elsif idfs.size == 1
96
- idf_file_name = idfs.first
97
- end
98
- end
99
-
100
- # Need to check the in.idf and in.osm
101
- # FileUtils.copy(options[:osm], "#{@run_directory}/in.osm")
102
- if idf_file_name
103
- FileUtils.copy(idf_file_name, "#{@run_directory}/in.idf")
104
- end
105
-
106
- # can't create symlinks because the /vagrant mount is actually a windows mount
107
- @time_logger.start('Copying EnergyPlus files')
108
- prepare_energyplus_dir
109
- @time_logger.stop('Copying EnergyPlus files')
110
-
111
- @time_logger.start('Running EnergyPlus Preprocess Script')
112
- energyplus_preprocess("#{@run_directory}/in.idf")
113
- @time_logger.start('Running EnergyPlus Preprocess Script')
114
-
115
- @time_logger.start('Running EnergyPlus')
116
- @results = call_energyplus
117
- @time_logger.stop('Running EnergyPlus')
118
-
119
- @results
120
- end
121
-
122
- private
123
-
124
- def find_energyplus
125
- if ENV['ENERGYPLUSDIR']
126
- return ENV['ENERGYPLUSDIR']
127
- # TODO: check if method exists! first
128
- elsif OpenStudio.respond_to? :getEnergyPlusDirectory
129
- return OpenStudio.getEnergyPlusDirectory.to_s
130
- elsif ENV['RUBYLIB'] =~ /OpenStudio/
131
- warn 'Finding EnergyPlus by RUBYLIB parsing will not be supported in the near future. Use either ENERGYPLUSDIR'\
132
- 'env variable or a newer OpenStudio version that has the getEnergyPlusDirectory method'
133
- path = ENV['RUBYLIB'].split(':')
134
- path = File.dirname(path.find { |p| p =~ /OpenStudio/ })
135
- # Grab the version out of the openstudio path
136
- path += '/sharedresources/EnergyPlus-8-3-0'
137
-
138
- return path
139
- else
140
- if /cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM
141
- return 'C:/EnergyPlus-8-3-0'
142
- else
143
- return '/usr/local/EnergyPlus-8-3-0'
144
- end
145
- end
146
- end
147
-
148
- def clean_directory
149
- @logger.info 'Removing any copied EnergyPlus files'
150
- @energyplus_files.each do |file|
151
- if File.exist? file
152
- FileUtils.rm_f file
153
- end
154
- end
155
-
156
- paths_to_rm = []
157
- paths_to_rm << "#{@run_directory}/packaged_measures"
158
- paths_to_rm << "#{@run_directory}/Energy+.ini"
159
- paths_to_rm.each { |p| FileUtils.rm_rf(p) if File.exist?(p) }
160
- end
161
-
162
- # Prepare the directory to run EnergyPlus. In EnergyPlus < 8.2, we have to copy all the files into the directory.
163
- #
164
- # @return [Boolean] Returns true is there is more than one file copied
165
- def prepare_energyplus_dir
166
- @logger.info "Copying EnergyPlus files to run directory: #{@run_directory}"
167
- Dir["#{@options[:energyplus_path]}/*"].each do |file|
168
- next if File.directory? file
169
- next if File.extname(file).downcase =~ /.pdf|.app|.html|.gif|.txt|.xlsx/
170
-
171
- dest_file = "#{@run_directory}/#{File.basename(file)}"
172
- @energyplus_files << dest_file
173
-
174
- @energyplus_exe = File.basename(dest_file) if File.basename(dest_file) =~ ENERGYPLUS_REGEX
175
- @expand_objects_exe = File.basename(dest_file) if File.basename(dest_file) =~ EXPAND_OBJECTS_REGEX
176
- FileUtils.copy file, dest_file
177
- end
178
-
179
- fail "Could not find EnergyPlus executable in #{@options[:energyplus_path]}" unless @energyplus_exe
180
- fail "Could not find ExpandObjects executable in #{@options[:energyplus_path]}" unless @expand_objects_exe
181
-
182
- @energyplus_files.size > 0
183
- end
184
-
185
- def call_energyplus
186
- begin
187
- current_dir = Dir.pwd
188
- Dir.chdir(@run_directory)
189
- @logger.info "Starting simulation in run directory: #{Dir.pwd}"
190
-
191
- File.open('stdout-expandobject', 'w') do |file|
192
- IO.popen("./#{@expand_objects_exe}") do |io|
193
- while (line = io.gets)
194
- file << line
195
- end
196
- end
197
- end
198
-
199
- # Check if expand objects did anythying
200
- if File.exist? 'expanded.idf'
201
- FileUtils.mv('in.idf', 'pre-expand.idf', force: true) if File.exist?('in.idf')
202
- FileUtils.mv('expanded.idf', 'in.idf', force: true)
203
- end
204
-
205
- # create stdout
206
- File.open('stdout-energyplus', 'w') do |file|
207
- IO.popen("./#{@energyplus_exe} 2>&1") do |io|
208
- while (line = io.gets)
209
- file << line
210
- end
211
- end
212
- end
213
- r = $?
214
-
215
- @logger.info "EnergyPlus returned '#{r}'"
216
- unless r == 0
217
- @logger.warn 'EnergyPlus returned a non-zero exit code. Check the stdout-energyplus log.'
218
- end
219
-
220
- if File.exist? 'eplusout.end'
221
- f = File.read('eplusout.end').force_encoding('ISO-8859-1').encode('utf-8', replace: nil)
222
- warnings_count = f[/(\d*).Warning/, 1]
223
- error_count = f[/(\d*).Severe.Errors/, 1]
224
- @logger.info "EnergyPlus finished with #{warnings_count} warnings and #{error_count} severe errors"
225
- if f =~ /EnergyPlus Terminated--Fatal Error Detected/
226
- fail 'EnergyPlus Terminated with a Fatal Error. Check eplusout.err log.'
227
- end
228
- else
229
- fail 'EnergyPlus failed and did not create an eplusout.end file. Check the stdout-energyplus log.'
230
- end
231
-
232
- if File.exist? 'eplusout.err'
233
- eplus_err = File.read('eplusout.err').force_encoding('ISO-8859-1').encode('utf-8', replace: nil)
234
- if eplus_err =~ /EnergyPlus Terminated--Fatal Error Detected/
235
- fail 'EnergyPlus Terminated with a Fatal Error. Check eplusout.err log.'
236
- end
237
- end
238
- rescue => e
239
- log_message = "#{__FILE__} failed with #{e.message}, #{e.backtrace.join("\n")}"
240
- @logger.error log_message
241
- raise log_message
242
- ensure
243
- @logger.info "Ensuring 'clean' directory"
244
- clean_directory
245
-
246
- Dir.chdir(current_dir)
247
- @logger.info 'EnergyPlus Completed'
248
- end
249
-
250
- {}
251
- end
252
-
253
- # Run this code before running energyplus to make sure the reporting variables are setup correctly
254
- def energyplus_preprocess(idf_filename)
255
- @logger.info 'Running EnergyPlus Preprocess'
256
-
257
- fail "Could not find IDF file in run directory (#{idf_filename})" unless File.exist? idf_filename
258
-
259
- new_objects = []
260
- needs_monthlyoutput = false
261
-
262
- idf = OpenStudio::IdfFile.load(idf_filename).get
263
- # save the pre-preprocess file
264
- File.open("#{File.dirname(idf_filename)}/pre-preprocess.idf", 'w') { |f| f << idf.to_s }
265
-
266
- needs_sqlobj = idf.getObjectsByType('Output:SQLite'.to_IddObjectType).empty?
267
-
268
- needs_monthlyoutput = idf.getObjectsByName('Building Energy Performance - Natural Gas').empty? ||
269
- idf.getObjectsByName('Building Energy Performance - Electricity').empty? ||
270
- idf.getObjectsByName('Building Energy Performance - District Heating').empty? ||
271
- idf.getObjectsByName('Building Energy Performance - District Cooling').empty?
272
-
273
- # this is a workaround for issue #1699 -- remove when 1699 is closed.
274
- new_objects << 'Output:Variable,*,Zone Air Temperature,Hourly;'
275
- new_objects << 'Output:Variable,*,Zone Air Relative Humidity,Daily;'
276
- new_objects << 'Output:Variable,*,Site Outdoor Air Drybulb Temperature,Monthly;'
277
- new_objects << 'Output:Variable,*,Site Outdoor Air Wetbulb Temperature,Timestep;'
278
-
279
- if needs_sqlobj
280
- @logger.info 'Adding SQL Output to IDF'
281
- new_objects << '
282
- Output:SQLite,
283
- SimpleAndTabular; ! Option Type
284
- '
285
- end
286
-
287
- if needs_monthlyoutput
288
- monthly_report_idf = File.join(File.dirname(__FILE__), 'monthly_report.idf')
289
- idf_file = OpenStudio::IdfFile.load(File.read(monthly_report_idf), 'EnergyPlus'.to_IddFileType).get
290
- idf.addObjects(idf_file.objects)
291
- end
292
-
293
- # These are supposedly needed for the calibration report
294
- new_objects << 'Output:Meter:MeterFileOnly,Gas:Facility,Daily;'
295
- new_objects << 'Output:Meter:MeterFileOnly,Electricity:Facility,Timestep;'
296
- new_objects << 'Output:Meter:MeterFileOnly,Electricity:Facility,Daily;'
297
-
298
- # Always add in the timestep facility meters
299
- new_objects << 'Output:Meter,Electricity:Facility,Timestep;'
300
- new_objects << 'Output:Meter,Gas:Facility,Timestep;'
301
- new_objects << 'Output:Meter,DistrictCooling:Facility,Timestep;'
302
- new_objects << 'Output:Meter,DistrictHeating:Facility,Timestep;'
303
-
304
- new_objects.each do |obj|
305
- object = OpenStudio::IdfObject.load(obj).get
306
- idf.addObject(object)
307
- end
308
-
309
- # save the file
310
- File.open(idf_filename, 'w') { |f| f << idf.to_s }
311
-
312
- @logger.info 'Finished EnergyPlus Preprocess'
313
- end
314
- end
@@ -1,230 +0,0 @@
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 RunOpenstudio
21
- # Mixin the MeasureApplication module to apply measures
22
- include OpenStudio::Workflow::ApplyMeasures
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, time_logger, adapter, workflow_arguments, past_results, options = {})
28
- defaults = { format: 'hash', analysis_root_path: '.' }
29
- warn 'Option of use_monthly_reports is deprecated. Monthly reports are always generated.' if options[:use_monthly_reports]
30
-
31
- @options = defaults.merge(options)
32
- @directory = directory
33
- # TODO: there is a base number of arguments that each job will need including @run_directory. abstract it out.
34
- @run_directory = "#{@directory}/run"
35
- @adapter = adapter
36
- @results = {}
37
- @logger = logger
38
- @time_logger = time_logger
39
- @workflow_arguments = workflow_arguments
40
- @past_results = past_results
41
- @logger.info "#{self.class} passed the following options #{@options}"
42
-
43
- # initialize instance variables that are needed in the perform section
44
- @model = nil
45
- @model_idf = nil
46
- @initial_weather_file = nil
47
- @weather_file_path = nil
48
- @analysis_json = nil
49
- # TODO: rename datapoint_json to just datapoint
50
- @datapoint_json = nil
51
- @output_attributes = {}
52
- @report_measures = []
53
- end
54
-
55
- def perform
56
- @logger.info "Calling #{__method__} in the #{self.class} class"
57
- @logger.info "Current directory is #{@directory}"
58
-
59
- @logger.info 'Retrieving datapoint and problem'
60
- @datapoint_json = @adapter.get_datapoint(@directory, @options)
61
- @analysis_json = @adapter.get_problem(@directory, @options)
62
-
63
- if @analysis_json && @analysis_json[:analysis]
64
- @model = load_seed_model
65
-
66
- load_weather_file
67
-
68
- apply_measures(:openstudio_measure)
69
- @logger.info('Finished applying OpenStudio measures.')
70
-
71
- @time_logger.start('Translating to EnergyPlus')
72
- translate_to_energyplus
73
- @time_logger.stop('Translating to EnergyPlus')
74
-
75
- apply_measures(:energyplus_measure)
76
- @logger.info('Finished applying EnergyPlus measures.')
77
-
78
- # check if the weather file has changed. This is cheesy for now. Should have a default measure that
79
- # always sets the weather file so that it can be better controlled
80
- updated_weather_file = get_weather_file_from_model
81
- unless updated_weather_file == @initial_weather_file
82
- # reset the result hash so the future processes know which weather file to run
83
- @logger.info "Updating the weather file to be '#{updated_weather_file}'"
84
- if (Pathname.new updated_weather_file).absolute? && (Pathname.new updated_weather_file).exist?
85
- @results[:weather_filename] = updated_weather_file
86
- else
87
- @results[:weather_filename] = "#{@weather_file_path}/#{updated_weather_file}"
88
- end
89
- end
90
-
91
- @logger.info 'Saving measure output attributes JSON'
92
- File.open("#{@run_directory}/measure_attributes.json", 'w') do |f|
93
- f << JSON.pretty_generate(@output_attributes)
94
- end
95
- end
96
-
97
- @time_logger.start('Saving OSM and IDF')
98
- save_osm_and_idf
99
- @time_logger.stop('Saving OSM and IDF')
100
-
101
- @results
102
- end
103
-
104
- private
105
-
106
- def save_osm_and_idf
107
- # save the data
108
- osm_filename = "#{@run_directory}/in.osm"
109
- File.open(osm_filename, 'w') { |f| f << @model.to_s }
110
-
111
- idf_filename = "#{@run_directory}/in.idf"
112
- File.open(idf_filename, 'w') { |f| f << @model_idf.to_s }
113
-
114
- @results[:osm] = File.expand_path(osm_filename)
115
- @results[:idf] = File.expand_path(idf_filename)
116
- end
117
-
118
- def load_seed_model
119
- model = nil
120
- @logger.info 'Loading seed model'
121
-
122
- baseline_model_path = nil
123
- # Unique case to use the previous generated OSM as the seed
124
- if @options[:run_xml] && @options[:run_xml][:osm_filename]
125
- if File.exist? @options[:run_xml][:osm_filename]
126
- baseline_model_path = @options[:run_xml][:osm_filename]
127
- end
128
- elsif @analysis_json[:analysis][:seed]
129
- @logger.info "Seed model is #{@analysis_json[:analysis][:seed]}"
130
- if @analysis_json[:analysis][:seed][:path]
131
-
132
- # assume that the seed model has been placed in the directory
133
- baseline_model_path = File.expand_path(
134
- File.join(@options[:analysis_root_path], @analysis_json[:analysis][:seed][:path]))
135
- else
136
- fail 'No seed model path in JSON defined'
137
- end
138
- else
139
- # TODO: create a blank model and return
140
- fail 'No seed model block'
141
- end
142
-
143
- if baseline_model_path
144
- if File.exist? baseline_model_path
145
- @logger.info "Reading in baseline model #{baseline_model_path}"
146
- translator = OpenStudio::OSVersion::VersionTranslator.new
147
- model = translator.loadModel(baseline_model_path)
148
- fail 'OpenStudio model is empty or could not be loaded' if model.empty?
149
- model = model.get
150
- else
151
- fail "Seed model '#{baseline_model_path}' did not exist"
152
- end
153
- else
154
- fail 'No baseline/seed model found'
155
- end
156
-
157
- model
158
- end
159
-
160
- # Save the weather file to the instance variable
161
- def load_weather_file
162
- @initial_weather_file = get_weather_file_from_model
163
-
164
- weather_filename = nil
165
- if @options[:run_xml] && @options[:run_xml][:weather_filename]
166
- if File.exist? @options[:run_xml][:weather_filename]
167
- weather_filename = @options[:run_xml][:weather_filename]
168
- end
169
- elsif @analysis_json[:analysis][:weather_file]
170
- if @analysis_json[:analysis][:weather_file][:path]
171
- weather_filename = File.expand_path(
172
- File.join(@options[:analysis_root_path], @analysis_json[:analysis][:weather_file][:path])
173
- )
174
- @weather_file_path = File.dirname(weather_filename)
175
- else
176
- fail 'No weather file path defined'
177
- end
178
- else
179
- fail 'No weather file block defined'
180
- end
181
-
182
- unless File.exist?(weather_filename)
183
- fail "Could not find weather file for simulation #{weather_filename}"
184
- end
185
-
186
- @results[:weather_filename] = weather_filename
187
-
188
- weather_filename
189
- end
190
-
191
- # return the weather file from the model. If the weather file is defined in the model, then
192
- # it checks the file paths to check if the model exists. This allows for a user to upload a
193
- # weather file in a measure and then have the measure's path be used for the weather file.
194
- def get_weather_file_from_model
195
- wf = nil
196
- # grab the weather file out of the OSM if it exists
197
- if @model.weatherFile.empty?
198
- @logger.info 'No weather file in model'
199
- else
200
- p = @model.weatherFile.get.path.get.to_s.gsub('file://', '')
201
- if File.exist? p
202
- # use this entire path
203
- @logger.info "Full path to weather file exists #{p}"
204
- wf = p
205
- else
206
- # this is the weather file from the OSM model
207
- wf = File.basename(@model.weatherFile.get.path.get.to_s)
208
- end
209
-
210
- # @logger.info "Initial model weather file is #{wf}" # unless model.weatherFile.empty?
211
- end
212
-
213
- wf
214
- end
215
-
216
- # Forward translate to energyplus
217
- def translate_to_energyplus
218
- if @model_idf.nil?
219
- @logger.info 'Translate object to EnergyPlus IDF in Prep for EnergyPlus Measure'
220
- a = Time.now
221
- # ensure objects exist for reporting purposes
222
- @model.getFacility
223
- @model.getBuilding
224
- forward_translator = OpenStudio::EnergyPlus::ForwardTranslator.new
225
- @model_idf = forward_translator.translateModel(@model)
226
- b = Time.now
227
- @logger.info "Translate object to EnergyPlus IDF took #{b.to_f - a.to_f}"
228
- end
229
- end
230
- end
@@ -1,110 +0,0 @@
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
- # Run precanned post processing to extract object functions
21
- # TODO: I hear that measures can step on each other if not run in their own directory
22
-
23
- require 'csv'
24
- require 'ostruct'
25
-
26
- class RunPostprocess
27
- # Mixin the MeasureApplication module to apply measures
28
- include OpenStudio::Workflow::ApplyMeasures
29
-
30
- def initialize(directory, logger, time_logger, adapter, workflow_arguments, past_results, options = {})
31
- defaults = {}
32
- @options = defaults.merge(options)
33
- @directory = directory
34
- @run_directory = "#{@directory}/run"
35
- @adapter = adapter
36
- @logger = logger
37
- @time_logger = time_logger
38
- @workflow_arguments = workflow_arguments
39
- @past_results = past_results
40
- @results = {}
41
- @output_attributes = {}
42
-
43
- @logger.info "#{self.class} passed the following options #{@options}"
44
- end
45
-
46
- def perform
47
- @logger.info "Calling #{__method__} in the #{self.class} class"
48
- @logger.info 'RunPostProcess Retrieving datapoint and problem'
49
-
50
- begin
51
- cleanup
52
- rescue => e
53
- log_message = "Runner error #{__FILE__} failed with #{e.message}, #{e.backtrace.join("\n")}"
54
- @logger.error log_message
55
- # raise log_message
56
- end
57
-
58
- @results
59
- end
60
-
61
- def cleanup
62
- # move any of the reporting file to the 'reports' directory for serverside access
63
- eplus_search_path = nil
64
- FileUtils.mkdir_p "#{@directory}/reports"
65
-
66
- # try to find the energyplus result file
67
- eplus_html = "#{@run_directory}/eplustbl.htm"
68
- unless File.exist? eplus_html
69
- eplus_html = Dir["#{@directory}/*EnergyPlus*/eplustbl.htm"].last || nil
70
- end
71
-
72
- if eplus_html
73
- if File.exist? eplus_html
74
- # do some encoding on the html if possible
75
- html = File.read(eplus_html)
76
- html = html.force_encoding('ISO-8859-1').encode('utf-8', replace: nil)
77
- File.open("#{@directory}/reports/eplustbl.html", 'w') { |f| f << html }
78
- end
79
- end
80
-
81
- # Also, find any "report*.*" files
82
- Dir["#{@run_directory}/*/report*.*"].each do |report|
83
- # get the parent directory of the file and snake case it
84
- # do i need to force encoding on this as well?
85
- measure_class_name = File.basename(File.dirname(report)).to_underscore
86
- file_ext = File.extname(report)
87
- append_str = File.basename(report, '.*')
88
- new_file_name = "#{@directory}/reports/#{measure_class_name}_#{append_str}#{file_ext}"
89
- FileUtils.copy report, new_file_name
90
- end
91
-
92
- # Remove empty directories in run folder
93
- Dir["#{@run_directory}/*"].select { |d| File.directory? d }.select { |d| (Dir.entries(d) - %w(. ..)).empty? }.each do |d|
94
- @logger.info "Removing empty directory #{d}"
95
- Dir.rmdir d
96
- end
97
-
98
- paths_to_rm = []
99
- # paths_to_rm << Pathname.glob("#{@run_directory}/*.osm")
100
- # paths_to_rm << Pathname.glob("#{@run_directory}/*.idf") # keep the idfs
101
- # paths_to_rm << Pathname.glob("*.audit")
102
- # paths_to_rm << Pathname.glob("*.bnd")
103
- # paths_to_rm << Pathname.glob("#{@run_directory}/*.eso")
104
- paths_to_rm << Pathname.glob("#{@run_directory}/*.mtr")
105
- paths_to_rm << Pathname.glob("#{@run_directory}/*.epw")
106
- paths_to_rm << Pathname.glob("#{@run_directory}/*.mtd")
107
- paths_to_rm << Pathname.glob("#{@run_directory}/*.rdd")
108
- paths_to_rm.each { |p| FileUtils.rm_rf(p) }
109
- end
110
- end