openstudio-workflow 1.2.1 → 1.2.2

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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +72 -72
  3. data/README.md +93 -48
  4. data/Rakefile +36 -36
  5. data/lib/openstudio-workflow.rb +49 -49
  6. data/lib/openstudio/workflow/adapters/input/local.rb +244 -240
  7. data/lib/openstudio/workflow/adapters/output/local.rb +95 -95
  8. data/lib/openstudio/workflow/adapters/output/socket.rb +91 -91
  9. data/lib/openstudio/workflow/adapters/output/web.rb +66 -66
  10. data/lib/openstudio/workflow/adapters/output_adapter.rb +147 -147
  11. data/lib/openstudio/workflow/job.rb +22 -22
  12. data/lib/openstudio/workflow/jobs/resources/monthly_report.idf +222 -222
  13. data/lib/openstudio/workflow/jobs/run_energyplus.rb +49 -49
  14. data/lib/openstudio/workflow/jobs/run_ep_measures.rb +55 -55
  15. data/lib/openstudio/workflow/jobs/run_initialization.rb +169 -167
  16. data/lib/openstudio/workflow/jobs/run_os_measures.rb +69 -69
  17. data/lib/openstudio/workflow/jobs/run_postprocess.rb +53 -53
  18. data/lib/openstudio/workflow/jobs/run_preprocess.rb +69 -69
  19. data/lib/openstudio/workflow/jobs/run_reporting_measures.rb +98 -98
  20. data/lib/openstudio/workflow/jobs/run_translation.rb +61 -61
  21. data/lib/openstudio/workflow/multi_delegator.rb +46 -46
  22. data/lib/openstudio/workflow/registry.rb +137 -137
  23. data/lib/openstudio/workflow/run.rb +299 -299
  24. data/lib/openstudio/workflow/time_logger.rb +53 -53
  25. data/lib/openstudio/workflow/util.rb +14 -14
  26. data/lib/openstudio/workflow/util/energyplus.rb +566 -564
  27. data/lib/openstudio/workflow/util/io.rb +33 -33
  28. data/lib/openstudio/workflow/util/measure.rb +588 -588
  29. data/lib/openstudio/workflow/util/model.rb +100 -100
  30. data/lib/openstudio/workflow/util/post_process.rb +187 -187
  31. data/lib/openstudio/workflow/util/weather_file.rb +108 -108
  32. data/lib/openstudio/workflow/version.rb +24 -24
  33. data/lib/openstudio/workflow_json.rb +426 -426
  34. data/lib/openstudio/workflow_runner.rb +233 -215
  35. metadata +3 -3
@@ -1,53 +1,53 @@
1
- # Class to store run times in a useful structure. Data are stored in a hash based on a the channel name
2
- # There is no concept of multi-levels. The onus is on the user to make sure that they don't add a value to the
3
- # logger that may be a level.
4
- class TimeLogger
5
- attr_reader :channels
6
-
7
- def initialize
8
- @logger = []
9
- @channels = {}
10
- end
11
-
12
- # name of the moniker that you are tracking. If the name is already in use, then it restarts the timer.
13
- def start(channel)
14
- # warning -- "will reset timer for #{moniker}" if @monikers.key? moniker
15
- s = ::Time.now
16
- @channels[channel] = { start_time_str: s.to_s, start_time: s.to_f }
17
- end
18
-
19
- def stop(channel)
20
- end_time = ::Time.now.to_f
21
- @logger << {
22
- channel: channel,
23
- start_time: @channels[channel][:start_time],
24
- start_time_str: @channels[channel][:start_time_str],
25
- end_time: end_time,
26
- delta: end_time - @channels[channel][:start_time]
27
- }
28
-
29
- # remove the channel
30
- @channels.delete(channel) if @channels.key? channel
31
- end
32
-
33
- def stop_all
34
- @channels.each_key do |channel|
35
- stop(channel)
36
- end
37
- end
38
-
39
- # return the entire report
40
- def report
41
- @logger
42
- end
43
-
44
- # this will report all the values for all the channels with this name.
45
- def delta(channel)
46
- @logger.map { |k| { channel.to_s => k[:delta] } if k[:channel] == channel }.compact
47
- end
48
-
49
- # save the data to a file. This will overwrite the file if it already exists
50
- def save(filename)
51
- File.open(filename, 'w') { |f| f << JSON.pretty_generate(@logger) }
52
- end
53
- end
1
+ # Class to store run times in a useful structure. Data are stored in a hash based on a the channel name
2
+ # There is no concept of multi-levels. The onus is on the user to make sure that they don't add a value to the
3
+ # logger that may be a level.
4
+ class TimeLogger
5
+ attr_reader :channels
6
+
7
+ def initialize
8
+ @logger = []
9
+ @channels = {}
10
+ end
11
+
12
+ # name of the moniker that you are tracking. If the name is already in use, then it restarts the timer.
13
+ def start(channel)
14
+ # warning -- "will reset timer for #{moniker}" if @monikers.key? moniker
15
+ s = ::Time.now
16
+ @channels[channel] = { start_time_str: s.to_s, start_time: s.to_f }
17
+ end
18
+
19
+ def stop(channel)
20
+ end_time = ::Time.now.to_f
21
+ @logger << {
22
+ channel: channel,
23
+ start_time: @channels[channel][:start_time],
24
+ start_time_str: @channels[channel][:start_time_str],
25
+ end_time: end_time,
26
+ delta: end_time - @channels[channel][:start_time]
27
+ }
28
+
29
+ # remove the channel
30
+ @channels.delete(channel) if @channels.key? channel
31
+ end
32
+
33
+ def stop_all
34
+ @channels.each_key do |channel|
35
+ stop(channel)
36
+ end
37
+ end
38
+
39
+ # return the entire report
40
+ def report
41
+ @logger
42
+ end
43
+
44
+ # this will report all the values for all the channels with this name.
45
+ def delta(channel)
46
+ @logger.map { |k| { channel.to_s => k[:delta] } if k[:channel] == channel }.compact
47
+ end
48
+
49
+ # save the data to a file. This will overwrite the file if it already exists
50
+ def save(filename)
51
+ File.open(filename, 'w') { |f| f << JSON.pretty_generate(@logger) }
52
+ end
53
+ end
@@ -1,14 +1,14 @@
1
- module OpenStudio
2
- module Workflow
3
- # Hard load utils for the moment
4
- #
5
- module Util
6
- require 'openstudio/workflow/util/io'
7
- require 'openstudio/workflow/util/measure'
8
- require 'openstudio/workflow/util/weather_file'
9
- require 'openstudio/workflow/util/model'
10
- require 'openstudio/workflow/util/energyplus'
11
- require 'openstudio/workflow/util/post_process'
12
- end
13
- end
14
- end
1
+ module OpenStudio
2
+ module Workflow
3
+ # Hard load utils for the moment
4
+ #
5
+ module Util
6
+ require 'openstudio/workflow/util/io'
7
+ require 'openstudio/workflow/util/measure'
8
+ require 'openstudio/workflow/util/weather_file'
9
+ require 'openstudio/workflow/util/model'
10
+ require 'openstudio/workflow/util/energyplus'
11
+ require 'openstudio/workflow/util/post_process'
12
+ end
13
+ end
14
+ end
@@ -1,564 +1,566 @@
1
- module OpenStudio
2
- module Workflow
3
- module Util
4
- # The methods needed to run simulations using EnergyPlus are stored here. See the run_simulation class for
5
- # implementation details.
6
- module EnergyPlus
7
- require 'openstudio/workflow/util/io'
8
- include OpenStudio::Workflow::Util::IO
9
- ENERGYPLUS_REGEX = /^energyplus\D{0,4}$/i
10
- EXPAND_OBJECTS_REGEX = /^expandobjects\D{0,4}$/i
11
-
12
- # Find the installation directory of EnergyPlus linked to the OpenStudio version being used
13
- #
14
- # @return [String] Returns the path to EnergyPlus
15
- #
16
- def find_energyplus
17
- path = OpenStudio.getEnergyPlusDirectory.to_s
18
- raise 'Unable to find the EnergyPlus executable' unless File.exist? path
19
- path
20
- end
21
-
22
- # Does something
23
- #
24
- # @param [String] run_directory Directory to run the EnergyPlus simulation in
25
- # @param [Array] energyplus_files Array of files containing the EnergyPlus and ExpandObjects EXEs
26
- # @return [Void]
27
- #
28
- def clean_directory(run_directory, energyplus_files, logger)
29
- logger.info 'Removing any copied EnergyPlus files'
30
- energyplus_files.each do |file|
31
- if File.exist? file
32
- FileUtils.rm_f file
33
- end
34
- end
35
-
36
- paths_to_rm = []
37
- paths_to_rm << "#{run_directory}/packaged_measures"
38
- paths_to_rm << "#{run_directory}/Energy+.ini"
39
- paths_to_rm.each { |p| FileUtils.rm_rf(p) if File.exist?(p) }
40
- end
41
-
42
- # Prepare the directory to run EnergyPlus
43
- #
44
- # @param [String] run_directory Directory to copy the required EnergyPlus files to
45
- # @param [Object] logger Logger object
46
- # @param [String] energyplus_path Path to the EnergyPlus EXE
47
- # @return [Array, file, file] Returns an array of strings of EnergyPlus files copied to the run_directory, the
48
- # ExpandObjects EXE file, and EnergyPlus EXE file
49
- #
50
- def prepare_energyplus_dir(run_directory, logger, energyplus_path = nil)
51
- logger.info "Copying EnergyPlus files to run directory: #{run_directory}"
52
- energyplus_path ||= find_energyplus
53
- logger.info "EnergyPlus path is #{energyplus_path}"
54
- energyplus_files = []
55
- energyplus_exe, expand_objects_exe = nil
56
- Dir["#{energyplus_path}/*"].each do |file|
57
- next if File.directory? file
58
- next if File.extname(file).downcase =~ /.pdf|.app|.html|.gif|.txt|.xlsx/
59
-
60
- dest_file = "#{run_directory}/#{File.basename(file)}"
61
- energyplus_files << dest_file
62
-
63
- # @todo (rhorsey) don't need to do this copy - DLM
64
- energyplus_exe = File.basename(dest_file) if File.basename(dest_file) =~ ENERGYPLUS_REGEX
65
- expand_objects_exe = File.basename(dest_file) if File.basename(dest_file) =~ EXPAND_OBJECTS_REGEX
66
- FileUtils.copy file, dest_file
67
- end
68
-
69
- raise "Could not find EnergyPlus executable in #{energyplus_path}" unless energyplus_exe
70
- raise "Could not find ExpandObjects executable in #{energyplus_path}" unless expand_objects_exe
71
-
72
- logger.info "EnergyPlus executable path is #{energyplus_exe}"
73
- logger.info "ExpandObjects executable path is #{expand_objects_exe}"
74
-
75
- return energyplus_files, energyplus_exe, expand_objects_exe
76
- end
77
-
78
- # Configures and executes the EnergyPlus simulation and checks to see if the simulation was successful
79
- #
80
- # @param [String] run_directory Directory to execute the EnergyPlus simulation in. It is assumed that this
81
- # directory already has the IDF and weather file in it
82
- # @param [String] energyplus_path (nil) Optional path to override the default path associated with the
83
- # OpenStudio package being used
84
- # @param [Object] output_adapter (nil) Optional output adapter to update
85
- # @param [Object] logger (nil) Optional logger, will log to STDOUT if none provided
86
- # @return [Void]
87
- #
88
- def call_energyplus(run_directory, energyplus_path = nil, output_adapter = nil, logger = nil, workflow_json = nil)
89
- logger ||= ::Logger.new(STDOUT) unless logger
90
-
91
- current_dir = Dir.pwd
92
- energyplus_path ||= find_energyplus
93
- logger.info "EnergyPlus path is #{energyplus_path}"
94
- energyplus_files, energyplus_exe, expand_objects_exe = prepare_energyplus_dir(run_directory, logger, energyplus_path)
95
- Dir.chdir(run_directory)
96
- logger.info "Starting simulation in run directory: #{Dir.pwd}"
97
-
98
- command = popen_command("./#{expand_objects_exe}")
99
- logger.info "Running command '#{command}'"
100
- File.open('stdout-expandobject', 'w') do |file|
101
- ::IO.popen(command) do |io|
102
- while (line = io.gets)
103
- file << line
104
- end
105
- end
106
- end
107
-
108
- # Check if expand objects did anything
109
- if File.exist? 'expanded.idf'
110
- FileUtils.mv('in.idf', 'pre-expand.idf', force: true) if File.exist?('in.idf')
111
- FileUtils.mv('expanded.idf', 'in.idf', force: true)
112
- end
113
-
114
- # create stdout
115
- command = popen_command("./#{energyplus_exe} 2>&1")
116
- logger.info "Running command '#{command}'"
117
- File.open('stdout-energyplus', 'w') do |file|
118
- ::IO.popen(command) do |io|
119
- while (line = io.gets)
120
- file << line
121
- output_adapter.communicate_energyplus_stdout(line) if output_adapter
122
- end
123
- end
124
- end
125
- r = $?
126
-
127
- logger.info "EnergyPlus returned '#{r}'"
128
- unless r.to_i.zero?
129
- logger.warn 'EnergyPlus returned a non-zero exit code. Check the stdout-energyplus log.'
130
- end
131
-
132
- if File.exist? 'eplusout.err'
133
- eplus_err = File.read('eplusout.err').force_encoding('ISO-8859-1').encode('utf-8', replace: nil)
134
-
135
- if workflow_json
136
- begin
137
- workflow_json.setEplusoutErr(eplus_err)
138
- rescue => e
139
- # older versions of OpenStudio did not have the setEplusoutErr method
140
- end
141
- end
142
-
143
- if eplus_err =~ /EnergyPlus Terminated--Fatal Error Detected/
144
- raise 'EnergyPlus Terminated with a Fatal Error. Check eplusout.err log.'
145
- end
146
- end
147
-
148
- if File.exist? 'eplusout.end'
149
- f = File.read('eplusout.end').force_encoding('ISO-8859-1').encode('utf-8', replace: nil)
150
- warnings_count = f[/(\d*).Warning/, 1]
151
- error_count = f[/(\d*).Severe.Errors/, 1]
152
- logger.info "EnergyPlus finished with #{warnings_count} warnings and #{error_count} severe errors"
153
- if f =~ /EnergyPlus Terminated--Fatal Error Detected/
154
- raise 'EnergyPlus Terminated with a Fatal Error. Check eplusout.err log.'
155
- end
156
- else
157
- raise 'EnergyPlus failed and did not create an eplusout.end file. Check the stdout-energyplus log.'
158
- end
159
-
160
- rescue => e
161
- log_message = "#{__FILE__} failed with #{e.message}, #{e.backtrace.join("\n")}"
162
- logger.error log_message
163
- raise log_message
164
- ensure
165
- logger.info "Ensuring 'clean' directory"
166
- clean_directory(run_directory, energyplus_files, logger)
167
-
168
- Dir.chdir(current_dir)
169
- logger.info 'EnergyPlus Completed'
170
- end
171
-
172
- # Run this code before running EnergyPlus to make sure the reporting variables are setup correctly
173
- #
174
- # @param [Object] idf The IDF Workspace to be simulated
175
- # @return [Void]
176
- #
177
- def energyplus_preprocess(idf, logger)
178
- logger.info 'Running EnergyPlus Preprocess'
179
-
180
- new_objects = []
181
-
182
- needs_sqlobj = idf.getObjectsByType('Output:SQLite'.to_IddObjectType).empty?
183
-
184
- if needs_sqlobj
185
- # just add this, we don't allow this type in add_energyplus_output_request
186
- logger.info 'Adding SQL Output to IDF'
187
- object = OpenStudio::IdfObject.load('Output:SQLite,SimpleAndTabular;').get
188
- idf.addObjects(object)
189
- end
190
-
191
- # merge in monthly reports
192
- EnergyPlus.monthly_report_idf_text.split(/^[\s]*$/).each do |object|
193
- object = object.strip
194
- next if object.empty?
195
-
196
- new_objects << object
197
- end
198
-
199
- # These are needed for the calibration report
200
- new_objects << 'Output:Meter:MeterFileOnly,Gas:Facility,Daily;'
201
- new_objects << 'Output:Meter:MeterFileOnly,Electricity:Facility,Timestep;'
202
- new_objects << 'Output:Meter:MeterFileOnly,Electricity:Facility,Daily;'
203
-
204
- # Always add in the timestep facility meters
205
- new_objects << 'Output:Meter,Electricity:Facility,Timestep;'
206
- new_objects << 'Output:Meter,Gas:Facility,Timestep;'
207
- new_objects << 'Output:Meter,DistrictCooling:Facility,Timestep;'
208
- new_objects << 'Output:Meter,DistrictHeating:Facility,Timestep;'
209
-
210
- new_objects.each do |obj|
211
- object = OpenStudio::IdfObject.load(obj).get
212
- OpenStudio::Workflow::Util::EnergyPlus.add_energyplus_output_request(idf, object)
213
- end
214
-
215
- # this is a workaround for issue #1699 -- remove when 1699 is closed.
216
- needs_hourly = true
217
- needs_timestep = true
218
- needs_daily = true
219
- needs_monthy = true
220
- idf.getObjectsByType('Output:Variable'.to_IddObjectType).each do |object|
221
- timestep = object.getString(2, true).get
222
- if /Hourly/i =~ timestep
223
- needs_hourly = false
224
- elsif /Timestep/i =~ timestep
225
- needs_timestep = false
226
- elsif /Daily/i =~ timestep
227
- needs_daily = false
228
- elsif /Monthly/i =~ timestep
229
- needs_monthy = false
230
- end
231
- end
232
-
233
- new_objects = []
234
- new_objects << 'Output:Variable,*,Zone Air Temperature,Hourly;' if needs_hourly
235
- new_objects << 'Output:Variable,*,Site Outdoor Air Wetbulb Temperature,Timestep;' if needs_timestep
236
- new_objects << 'Output:Variable,*,Zone Air Relative Humidity,Daily;' if needs_daily
237
- new_objects << 'Output:Variable,*,Site Outdoor Air Drybulb Temperature,Monthly;' if needs_monthy
238
-
239
- new_objects.each do |obj|
240
- object = OpenStudio::IdfObject.load(obj).get
241
- OpenStudio::Workflow::Util::EnergyPlus.add_energyplus_output_request(idf, object)
242
- end
243
-
244
- logger.info 'Finished EnergyPlus Preprocess'
245
- end
246
-
247
- # examines object and determines whether or not to add it to the workspace
248
- def self.add_energyplus_output_request(workspace, idf_object)
249
- num_added = 0
250
- idd_object = idf_object.iddObject
251
-
252
- allowed_objects = []
253
- allowed_objects << 'Output:Surfaces:List'
254
- allowed_objects << 'Output:Surfaces:Drawing'
255
- allowed_objects << 'Output:Schedules'
256
- allowed_objects << 'Output:Constructions'
257
- allowed_objects << 'Output:Table:TimeBins'
258
- allowed_objects << 'Output:Table:Monthly'
259
- allowed_objects << 'Output:Variable'
260
- allowed_objects << 'Output:Meter'
261
- allowed_objects << 'Output:Meter:MeterFileOnly'
262
- allowed_objects << 'Output:Meter:Cumulative'
263
- allowed_objects << 'Output:Meter:Cumulative:MeterFileOnly'
264
- allowed_objects << 'Meter:Custom'
265
- allowed_objects << 'Meter:CustomDecrement'
266
-
267
- if allowed_objects.include?(idd_object.name)
268
- unless check_for_object(workspace, idf_object, idd_object.type)
269
- workspace.addObject(idf_object)
270
- num_added += 1
271
- end
272
- end
273
-
274
- allowed_unique_objects = []
275
- # allowed_unique_objects << "Output:EnergyManagementSystem" # TODO: have to merge
276
- # allowed_unique_objects << "OutputControl:SurfaceColorScheme" # TODO: have to merge
277
- allowed_unique_objects << 'Output:Table:SummaryReports' # TODO: have to merge
278
- # OutputControl:Table:Style # not allowed
279
- # OutputControl:ReportingTolerances # not allowed
280
- # Output:SQLite # not allowed
281
-
282
- if allowed_unique_objects.include?(idf_object.iddObject.name)
283
- if idf_object.iddObject.name == 'Output:Table:SummaryReports'
284
- summary_reports = workspace.getObjectsByType(idf_object.iddObject.type)
285
- if summary_reports.empty?
286
- workspace.addObject(idf_object)
287
- num_added += 1
288
- else
289
- merge_output_table_summary_reports(summary_reports[0], idf_object)
290
- end
291
- end
292
- end
293
-
294
- return num_added
295
- end
296
-
297
- # check to see if we have an exact match for this object already
298
- def self.check_for_object(workspace, idf_object, idd_object_type)
299
- workspace.getObjectsByType(idd_object_type).each do |object|
300
- # all of these objects fields are data fields
301
- if idf_object.dataFieldsEqual(object)
302
- return true
303
- end
304
- end
305
- return false
306
- end
307
-
308
- # merge all summary reports that are not in the current workspace
309
- def self.merge_output_table_summary_reports(current_object, new_object)
310
- current_fields = []
311
- current_object.extensibleGroups.each do |current_extensible_group|
312
- current_fields << current_extensible_group.getString(0).to_s
313
- end
314
-
315
- fields_to_add = []
316
- new_object.extensibleGroups.each do |new_extensible_group|
317
- field = new_extensible_group.getString(0).to_s
318
- unless current_fields.include?(field)
319
- current_fields << field
320
- fields_to_add << field
321
- end
322
- end
323
-
324
- unless fields_to_add.empty?
325
- fields_to_add.each do |field|
326
- values = OpenStudio::StringVector.new
327
- values << field
328
- current_object.pushExtensibleGroup(values)
329
- end
330
- return true
331
- end
332
-
333
- return false
334
- end
335
-
336
- def self.monthly_report_idf_text
337
- <<-HEREDOC
338
- Output:Table:Monthly,
339
- Building Energy Performance - Electricity, !- Name
340
- 2, !- Digits After Decimal
341
- InteriorLights:Electricity, !- Variable or Meter 1 Name
342
- SumOrAverage, !- Aggregation Type for Variable or Meter 1
343
- ExteriorLights:Electricity, !- Variable or Meter 2 Name
344
- SumOrAverage, !- Aggregation Type for Variable or Meter 2
345
- InteriorEquipment:Electricity, !- Variable or Meter 3 Name
346
- SumOrAverage, !- Aggregation Type for Variable or Meter 3
347
- ExteriorEquipment:Electricity, !- Variable or Meter 4 Name
348
- SumOrAverage, !- Aggregation Type for Variable or Meter 4
349
- Fans:Electricity, !- Variable or Meter 5 Name
350
- SumOrAverage, !- Aggregation Type for Variable or Meter 5
351
- Pumps:Electricity, !- Variable or Meter 6 Name
352
- SumOrAverage, !- Aggregation Type for Variable or Meter 6
353
- Heating:Electricity, !- Variable or Meter 7 Name
354
- SumOrAverage, !- Aggregation Type for Variable or Meter 7
355
- Cooling:Electricity, !- Variable or Meter 8 Name
356
- SumOrAverage, !- Aggregation Type for Variable or Meter 8
357
- HeatRejection:Electricity, !- Variable or Meter 9 Name
358
- SumOrAverage, !- Aggregation Type for Variable or Meter 9
359
- Humidifier:Electricity, !- Variable or Meter 10 Name
360
- SumOrAverage, !- Aggregation Type for Variable or Meter 10
361
- HeatRecovery:Electricity,!- Variable or Meter 11 Name
362
- SumOrAverage, !- Aggregation Type for Variable or Meter 11
363
- WaterSystems:Electricity,!- Variable or Meter 12 Name
364
- SumOrAverage, !- Aggregation Type for Variable or Meter 12
365
- Cogeneration:Electricity,!- Variable or Meter 13 Name
366
- SumOrAverage, !- Aggregation Type for Variable or Meter 13
367
- Refrigeration:Electricity,!- Variable or Meter 14 Name
368
- SumOrAverage; !- Aggregation Type for Variable or Meter 14
369
-
370
- Output:Table:Monthly,
371
- Building Energy Performance - Natural Gas, !- Name
372
- 2, !- Digits After Decimal
373
- InteriorEquipment:Gas, !- Variable or Meter 1 Name
374
- SumOrAverage, !- Aggregation Type for Variable or Meter 1
375
- ExteriorEquipment:Gas, !- Variable or Meter 2 Name
376
- SumOrAverage, !- Aggregation Type for Variable or Meter 2
377
- Heating:Gas, !- Variable or Meter 3 Name
378
- SumOrAverage, !- Aggregation Type for Variable or Meter 3
379
- Cooling:Gas, !- Variable or Meter 4 Name
380
- SumOrAverage, !- Aggregation Type for Variable or Meter 4
381
- WaterSystems:Gas, !- Variable or Meter 5 Name
382
- SumOrAverage, !- Aggregation Type for Variable or Meter 5
383
- Cogeneration:Gas, !- Variable or Meter 6 Name
384
- SumOrAverage; !- Aggregation Type for Variable or Meter 6
385
-
386
- Output:Table:Monthly,
387
- Building Energy Performance - District Heating, !- Name
388
- 2, !- Digits After Decimal
389
- InteriorLights:DistrictHeating, !- Variable or Meter 1 Name
390
- SumOrAverage, !- Aggregation Type for Variable or Meter 1
391
- ExteriorLights:DistrictHeating, !- Variable or Meter 2 Name
392
- SumOrAverage, !- Aggregation Type for Variable or Meter 2
393
- InteriorEquipment:DistrictHeating, !- Variable or Meter 3 Name
394
- SumOrAverage, !- Aggregation Type for Variable or Meter 3
395
- ExteriorEquipment:DistrictHeating, !- Variable or Meter 4 Name
396
- SumOrAverage, !- Aggregation Type for Variable or Meter 4
397
- Fans:DistrictHeating, !- Variable or Meter 5 Name
398
- SumOrAverage, !- Aggregation Type for Variable or Meter 5
399
- Pumps:DistrictHeating, !- Variable or Meter 6 Name
400
- SumOrAverage, !- Aggregation Type for Variable or Meter 6
401
- Heating:DistrictHeating, !- Variable or Meter 7 Name
402
- SumOrAverage, !- Aggregation Type for Variable or Meter 7
403
- Cooling:DistrictHeating, !- Variable or Meter 8 Name
404
- SumOrAverage, !- Aggregation Type for Variable or Meter 8
405
- HeatRejection:DistrictHeating, !- Variable or Meter 9 Name
406
- SumOrAverage, !- Aggregation Type for Variable or Meter 9
407
- Humidifier:DistrictHeating, !- Variable or Meter 10 Name
408
- SumOrAverage, !- Aggregation Type for Variable or Meter 10
409
- HeatRecovery:DistrictHeating,!- Variable or Meter 11 Name
410
- SumOrAverage, !- Aggregation Type for Variable or Meter 11
411
- WaterSystems:DistrictHeating,!- Variable or Meter 12 Name
412
- SumOrAverage, !- Aggregation Type for Variable or Meter 12
413
- Cogeneration:DistrictHeating,!- Variable or Meter 13 Name
414
- SumOrAverage; !- Aggregation Type for Variable or Meter 13
415
-
416
- Output:Table:Monthly,
417
- Building Energy Performance - District Cooling, !- Name
418
- 2, !- Digits After Decimal
419
- InteriorLights:DistrictCooling, !- Variable or Meter 1 Name
420
- SumOrAverage, !- Aggregation Type for Variable or Meter 1
421
- ExteriorLights:DistrictCooling, !- Variable or Meter 2 Name
422
- SumOrAverage, !- Aggregation Type for Variable or Meter 2
423
- InteriorEquipment:DistrictCooling, !- Variable or Meter 3 Name
424
- SumOrAverage, !- Aggregation Type for Variable or Meter 3
425
- ExteriorEquipment:DistrictCooling, !- Variable or Meter 4 Name
426
- SumOrAverage, !- Aggregation Type for Variable or Meter 4
427
- Fans:DistrictCooling, !- Variable or Meter 5 Name
428
- SumOrAverage, !- Aggregation Type for Variable or Meter 5
429
- Pumps:DistrictCooling, !- Variable or Meter 6 Name
430
- SumOrAverage, !- Aggregation Type for Variable or Meter 6
431
- Heating:DistrictCooling, !- Variable or Meter 7 Name
432
- SumOrAverage, !- Aggregation Type for Variable or Meter 7
433
- Cooling:DistrictCooling, !- Variable or Meter 8 Name
434
- SumOrAverage, !- Aggregation Type for Variable or Meter 8
435
- HeatRejection:DistrictCooling, !- Variable or Meter 9 Name
436
- SumOrAverage, !- Aggregation Type for Variable or Meter 9
437
- Humidifier:DistrictCooling, !- Variable or Meter 10 Name
438
- SumOrAverage, !- Aggregation Type for Variable or Meter 10
439
- HeatRecovery:DistrictCooling,!- Variable or Meter 11 Name
440
- SumOrAverage, !- Aggregation Type for Variable or Meter 11
441
- WaterSystems:DistrictCooling,!- Variable or Meter 12 Name
442
- SumOrAverage, !- Aggregation Type for Variable or Meter 12
443
- Cogeneration:DistrictCooling,!- Variable or Meter 13 Name
444
- SumOrAverage; !- Aggregation Type for Variable or Meter 13
445
-
446
- Output:Table:Monthly,
447
- Building Energy Performance - Electricity Peak Demand, !- Name
448
- 2, !- Digits After Decimal
449
- Electricity:Facility, !- Variable or Meter 1 Name
450
- Maximum, !- Aggregation Type for Variable or Meter 1
451
- InteriorLights:Electricity, !- Variable or Meter 1 Name
452
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 1
453
- ExteriorLights:Electricity, !- Variable or Meter 2 Name
454
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 2
455
- InteriorEquipment:Electricity, !- Variable or Meter 3 Name
456
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 3
457
- ExteriorEquipment:Electricity, !- Variable or Meter 4 Name
458
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 4
459
- Fans:Electricity, !- Variable or Meter 5 Name
460
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 5
461
- Pumps:Electricity, !- Variable or Meter 6 Name
462
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 6
463
- Heating:Electricity, !- Variable or Meter 7 Name
464
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 7
465
- Cooling:Electricity, !- Variable or Meter 8 Name
466
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 8
467
- HeatRejection:Electricity, !- Variable or Meter 9 Name
468
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 9
469
- Humidifier:Electricity, !- Variable or Meter 10 Name
470
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 10
471
- HeatRecovery:Electricity,!- Variable or Meter 11 Name
472
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 11
473
- WaterSystems:Electricity,!- Variable or Meter 12 Name
474
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 12
475
- Cogeneration:Electricity,!- Variable or Meter 13 Name
476
- ValueWhenMaximumOrMinimum; !- Aggregation Type for Variable or Meter 13
477
-
478
- Output:Table:Monthly,
479
- Building Energy Performance - Natural Gas Peak Demand, !- Name
480
- 2, !- Digits After Decimal
481
- Gas:Facility, !- Variable or Meter 1 Name
482
- Maximum, !- Aggregation Type for Variable or Meter 1
483
- InteriorEquipment:Gas, !- Variable or Meter 1 Name
484
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 1
485
- ExteriorEquipment:Gas, !- Variable or Meter 2 Name
486
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 2
487
- Heating:Gas, !- Variable or Meter 3 Name
488
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 3
489
- Cooling:Gas, !- Variable or Meter 4 Name
490
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 4
491
- WaterSystems:Gas, !- Variable or Meter 5 Name
492
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 5
493
- Cogeneration:Gas, !- Variable or Meter 6 Name
494
- ValueWhenMaximumOrMinimum; !- Aggregation Type for Variable or Meter 6
495
-
496
- Output:Table:Monthly,
497
- Building Energy Performance - District Heating Peak Demand, !- Name
498
- 2, !- Digits After Decimal
499
- DistrictHeating:Facility, !- Variable or Meter 1 Name
500
- Maximum, !- Aggregation Type for Variable or Meter 1
501
- InteriorLights:DistrictHeating, !- Variable or Meter 1 Name
502
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 1
503
- ExteriorLights:DistrictHeating, !- Variable or Meter 2 Name
504
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 2
505
- InteriorEquipment:DistrictHeating, !- Variable or Meter 3 Name
506
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 3
507
- ExteriorEquipment:DistrictHeating, !- Variable or Meter 4 Name
508
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 4
509
- Fans:DistrictHeating, !- Variable or Meter 5 Name
510
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 5
511
- Pumps:DistrictHeating, !- Variable or Meter 6 Name
512
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 6
513
- Heating:DistrictHeating, !- Variable or Meter 7 Name
514
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 7
515
- Cooling:DistrictHeating, !- Variable or Meter 8 Name
516
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 8
517
- HeatRejection:DistrictHeating, !- Variable or Meter 9 Name
518
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 9
519
- Humidifier:DistrictHeating, !- Variable or Meter 10 Name
520
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 10
521
- HeatRecovery:DistrictHeating,!- Variable or Meter 11 Name
522
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 11
523
- WaterSystems:DistrictHeating,!- Variable or Meter 12 Name
524
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 12
525
- Cogeneration:DistrictHeating,!- Variable or Meter 13 Name
526
- ValueWhenMaximumOrMinimum; !- Aggregation Type for Variable or Meter 13
527
-
528
- Output:Table:Monthly,
529
- Building Energy Performance - District Cooling Peak Demand, !- Name
530
- 2, !- Digits After Decimal
531
- DistrictCooling:Facility, !- Variable or Meter 1 Name
532
- Maximum, !- Aggregation Type for Variable or Meter 1
533
- InteriorLights:DistrictCooling, !- Variable or Meter 1 Name
534
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 1
535
- ExteriorLights:DistrictCooling, !- Variable or Meter 2 Name
536
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 2
537
- InteriorEquipment:DistrictCooling, !- Variable or Meter 3 Name
538
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 3
539
- ExteriorEquipment:DistrictCooling, !- Variable or Meter 4 Name
540
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 4
541
- Fans:DistrictCooling, !- Variable or Meter 5 Name
542
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 5
543
- Pumps:DistrictCooling, !- Variable or Meter 6 Name
544
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 6
545
- Heating:DistrictCooling, !- Variable or Meter 7 Name
546
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 7
547
- Cooling:DistrictCooling, !- Variable or Meter 8 Name
548
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 8
549
- HeatRejection:DistrictCooling, !- Variable or Meter 9 Name
550
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 9
551
- Humidifier:DistrictCooling, !- Variable or Meter 10 Name
552
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 10
553
- HeatRecovery:DistrictCooling,!- Variable or Meter 11 Name
554
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 11
555
- WaterSystems:DistrictCooling,!- Variable or Meter 12 Name
556
- ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 12
557
- Cogeneration:DistrictCooling,!- Variable or Meter 13 Name
558
- ValueWhenMaximumOrMinimum; !- Aggregation Type for Variable or Meter 13
559
- HEREDOC
560
- end
561
- end
562
- end
563
- end
564
- end
1
+ module OpenStudio
2
+ module Workflow
3
+ module Util
4
+ # The methods needed to run simulations using EnergyPlus are stored here. See the run_simulation class for
5
+ # implementation details.
6
+ module EnergyPlus
7
+ require 'openstudio/workflow/util/io'
8
+ include OpenStudio::Workflow::Util::IO
9
+ ENERGYPLUS_REGEX = /^energyplus\D{0,4}$/i
10
+ EXPAND_OBJECTS_REGEX = /^expandobjects\D{0,4}$/i
11
+
12
+ # Find the installation directory of EnergyPlus linked to the OpenStudio version being used
13
+ #
14
+ # @return [String] Returns the path to EnergyPlus
15
+ #
16
+ def find_energyplus
17
+ path = OpenStudio.getEnergyPlusDirectory.to_s
18
+ raise 'Unable to find the EnergyPlus executable' unless File.exist? path
19
+ path
20
+ end
21
+
22
+ # Does something
23
+ #
24
+ # @param [String] run_directory Directory to run the EnergyPlus simulation in
25
+ # @param [Array] energyplus_files Array of files containing the EnergyPlus and ExpandObjects EXEs
26
+ # @return [Void]
27
+ #
28
+ def clean_directory(run_directory, energyplus_files, logger)
29
+ logger.info 'Removing any copied EnergyPlus files'
30
+ energyplus_files.each do |file|
31
+ if File.exist? file
32
+ FileUtils.rm_f file
33
+ end
34
+ end
35
+
36
+ paths_to_rm = []
37
+ paths_to_rm << "#{run_directory}/packaged_measures"
38
+ paths_to_rm << "#{run_directory}/Energy+.ini"
39
+ paths_to_rm.each { |p| FileUtils.rm_rf(p) if File.exist?(p) }
40
+ end
41
+
42
+ # Prepare the directory to run EnergyPlus
43
+ #
44
+ # @param [String] run_directory Directory to copy the required EnergyPlus files to
45
+ # @param [Object] logger Logger object
46
+ # @param [String] energyplus_path Path to the EnergyPlus EXE
47
+ # @return [Array, file, file] Returns an array of strings of EnergyPlus files copied to the run_directory, the
48
+ # ExpandObjects EXE file, and EnergyPlus EXE file
49
+ #
50
+ def prepare_energyplus_dir(run_directory, logger, energyplus_path = nil)
51
+ logger.info "Copying EnergyPlus files to run directory: #{run_directory}"
52
+ energyplus_path ||= find_energyplus
53
+ logger.info "EnergyPlus path is #{energyplus_path}"
54
+ energyplus_files = []
55
+ energyplus_exe, expand_objects_exe = nil
56
+ Dir["#{energyplus_path}/*"].each do |file|
57
+ next if File.directory? file
58
+
59
+ # copy idd and ini files
60
+ if File.extname(file).downcase =~ /.idd|.ini/
61
+ dest_file = "#{run_directory}/#{File.basename(file)}"
62
+ energyplus_files << dest_file
63
+ FileUtils.copy file, dest_file
64
+ end
65
+
66
+ energyplus_exe = file if File.basename(file) =~ ENERGYPLUS_REGEX
67
+ expand_objects_exe = file if File.basename(file) =~ EXPAND_OBJECTS_REGEX
68
+
69
+ end
70
+
71
+ raise "Could not find EnergyPlus executable in #{energyplus_path}" unless energyplus_exe
72
+ raise "Could not find ExpandObjects executable in #{energyplus_path}" unless expand_objects_exe
73
+
74
+ logger.info "EnergyPlus executable path is #{energyplus_exe}"
75
+ logger.info "ExpandObjects executable path is #{expand_objects_exe}"
76
+
77
+ return energyplus_files, energyplus_exe, expand_objects_exe
78
+ end
79
+
80
+ # Configures and executes the EnergyPlus simulation and checks to see if the simulation was successful
81
+ #
82
+ # @param [String] run_directory Directory to execute the EnergyPlus simulation in. It is assumed that this
83
+ # directory already has the IDF and weather file in it
84
+ # @param [String] energyplus_path (nil) Optional path to override the default path associated with the
85
+ # OpenStudio package being used
86
+ # @param [Object] output_adapter (nil) Optional output adapter to update
87
+ # @param [Object] logger (nil) Optional logger, will log to STDOUT if none provided
88
+ # @return [Void]
89
+ #
90
+ def call_energyplus(run_directory, energyplus_path = nil, output_adapter = nil, logger = nil, workflow_json = nil)
91
+ logger ||= ::Logger.new(STDOUT) unless logger
92
+
93
+ current_dir = Dir.pwd
94
+ energyplus_path ||= find_energyplus
95
+ logger.info "EnergyPlus path is #{energyplus_path}"
96
+ energyplus_files, energyplus_exe, expand_objects_exe = prepare_energyplus_dir(run_directory, logger, energyplus_path)
97
+ Dir.chdir(run_directory)
98
+ logger.info "Starting simulation in run directory: #{Dir.pwd}"
99
+
100
+ command = popen_command("\"#{expand_objects_exe}\"")
101
+ logger.info "Running command '#{command}'"
102
+ File.open('stdout-expandobject', 'w') do |file|
103
+ ::IO.popen(command) do |io|
104
+ while (line = io.gets)
105
+ file << line
106
+ end
107
+ end
108
+ end
109
+
110
+ # Check if expand objects did anything
111
+ if File.exist? 'expanded.idf'
112
+ FileUtils.mv('in.idf', 'pre-expand.idf', force: true) if File.exist?('in.idf')
113
+ FileUtils.mv('expanded.idf', 'in.idf', force: true)
114
+ end
115
+
116
+ # create stdout
117
+ command = popen_command("\"#{energyplus_exe}\" 2>&1")
118
+ logger.info "Running command '#{command}'"
119
+ File.open('stdout-energyplus', 'w') do |file|
120
+ ::IO.popen(command) do |io|
121
+ while (line = io.gets)
122
+ file << line
123
+ output_adapter.communicate_energyplus_stdout(line) if output_adapter
124
+ end
125
+ end
126
+ end
127
+ r = $?
128
+
129
+ logger.info "EnergyPlus returned '#{r}'"
130
+ unless r.to_i.zero?
131
+ logger.warn 'EnergyPlus returned a non-zero exit code. Check the stdout-energyplus log.'
132
+ end
133
+
134
+ if File.exist? 'eplusout.err'
135
+ eplus_err = File.read('eplusout.err').force_encoding('ISO-8859-1').encode('utf-8', replace: nil)
136
+
137
+ if workflow_json
138
+ begin
139
+ workflow_json.setEplusoutErr(eplus_err)
140
+ rescue => e
141
+ # older versions of OpenStudio did not have the setEplusoutErr method
142
+ end
143
+ end
144
+
145
+ if eplus_err =~ /EnergyPlus Terminated--Fatal Error Detected/
146
+ raise 'EnergyPlus Terminated with a Fatal Error. Check eplusout.err log.'
147
+ end
148
+ end
149
+
150
+ if File.exist? 'eplusout.end'
151
+ f = File.read('eplusout.end').force_encoding('ISO-8859-1').encode('utf-8', replace: nil)
152
+ warnings_count = f[/(\d*).Warning/, 1]
153
+ error_count = f[/(\d*).Severe.Errors/, 1]
154
+ logger.info "EnergyPlus finished with #{warnings_count} warnings and #{error_count} severe errors"
155
+ if f =~ /EnergyPlus Terminated--Fatal Error Detected/
156
+ raise 'EnergyPlus Terminated with a Fatal Error. Check eplusout.err log.'
157
+ end
158
+ else
159
+ raise 'EnergyPlus failed and did not create an eplusout.end file. Check the stdout-energyplus log.'
160
+ end
161
+
162
+ rescue => e
163
+ log_message = "#{__FILE__} failed with #{e.message}, #{e.backtrace.join("\n")}"
164
+ logger.error log_message
165
+ raise log_message
166
+ ensure
167
+ logger.info "Ensuring 'clean' directory"
168
+ clean_directory(run_directory, energyplus_files, logger)
169
+
170
+ Dir.chdir(current_dir)
171
+ logger.info 'EnergyPlus Completed'
172
+ end
173
+
174
+ # Run this code before running EnergyPlus to make sure the reporting variables are setup correctly
175
+ #
176
+ # @param [Object] idf The IDF Workspace to be simulated
177
+ # @return [Void]
178
+ #
179
+ def energyplus_preprocess(idf, logger)
180
+ logger.info 'Running EnergyPlus Preprocess'
181
+
182
+ new_objects = []
183
+
184
+ needs_sqlobj = idf.getObjectsByType('Output:SQLite'.to_IddObjectType).empty?
185
+
186
+ if needs_sqlobj
187
+ # just add this, we don't allow this type in add_energyplus_output_request
188
+ logger.info 'Adding SQL Output to IDF'
189
+ object = OpenStudio::IdfObject.load('Output:SQLite,SimpleAndTabular;').get
190
+ idf.addObjects(object)
191
+ end
192
+
193
+ # merge in monthly reports
194
+ EnergyPlus.monthly_report_idf_text.split(/^[\s]*$/).each do |object|
195
+ object = object.strip
196
+ next if object.empty?
197
+
198
+ new_objects << object
199
+ end
200
+
201
+ # These are needed for the calibration report
202
+ new_objects << 'Output:Meter:MeterFileOnly,Gas:Facility,Daily;'
203
+ new_objects << 'Output:Meter:MeterFileOnly,Electricity:Facility,Timestep;'
204
+ new_objects << 'Output:Meter:MeterFileOnly,Electricity:Facility,Daily;'
205
+
206
+ # Always add in the timestep facility meters
207
+ new_objects << 'Output:Meter,Electricity:Facility,Timestep;'
208
+ new_objects << 'Output:Meter,Gas:Facility,Timestep;'
209
+ new_objects << 'Output:Meter,DistrictCooling:Facility,Timestep;'
210
+ new_objects << 'Output:Meter,DistrictHeating:Facility,Timestep;'
211
+
212
+ new_objects.each do |obj|
213
+ object = OpenStudio::IdfObject.load(obj).get
214
+ OpenStudio::Workflow::Util::EnergyPlus.add_energyplus_output_request(idf, object)
215
+ end
216
+
217
+ # this is a workaround for issue #1699 -- remove when 1699 is closed.
218
+ needs_hourly = true
219
+ needs_timestep = true
220
+ needs_daily = true
221
+ needs_monthy = true
222
+ idf.getObjectsByType('Output:Variable'.to_IddObjectType).each do |object|
223
+ timestep = object.getString(2, true).get
224
+ if /Hourly/i =~ timestep
225
+ needs_hourly = false
226
+ elsif /Timestep/i =~ timestep
227
+ needs_timestep = false
228
+ elsif /Daily/i =~ timestep
229
+ needs_daily = false
230
+ elsif /Monthly/i =~ timestep
231
+ needs_monthy = false
232
+ end
233
+ end
234
+
235
+ new_objects = []
236
+ new_objects << 'Output:Variable,*,Zone Air Temperature,Hourly;' if needs_hourly
237
+ new_objects << 'Output:Variable,*,Site Outdoor Air Wetbulb Temperature,Timestep;' if needs_timestep
238
+ new_objects << 'Output:Variable,*,Zone Air Relative Humidity,Daily;' if needs_daily
239
+ new_objects << 'Output:Variable,*,Site Outdoor Air Drybulb Temperature,Monthly;' if needs_monthy
240
+
241
+ new_objects.each do |obj|
242
+ object = OpenStudio::IdfObject.load(obj).get
243
+ OpenStudio::Workflow::Util::EnergyPlus.add_energyplus_output_request(idf, object)
244
+ end
245
+
246
+ logger.info 'Finished EnergyPlus Preprocess'
247
+ end
248
+
249
+ # examines object and determines whether or not to add it to the workspace
250
+ def self.add_energyplus_output_request(workspace, idf_object)
251
+ num_added = 0
252
+ idd_object = idf_object.iddObject
253
+
254
+ allowed_objects = []
255
+ allowed_objects << 'Output:Surfaces:List'
256
+ allowed_objects << 'Output:Surfaces:Drawing'
257
+ allowed_objects << 'Output:Schedules'
258
+ allowed_objects << 'Output:Constructions'
259
+ allowed_objects << 'Output:Table:TimeBins'
260
+ allowed_objects << 'Output:Table:Monthly'
261
+ allowed_objects << 'Output:Variable'
262
+ allowed_objects << 'Output:Meter'
263
+ allowed_objects << 'Output:Meter:MeterFileOnly'
264
+ allowed_objects << 'Output:Meter:Cumulative'
265
+ allowed_objects << 'Output:Meter:Cumulative:MeterFileOnly'
266
+ allowed_objects << 'Meter:Custom'
267
+ allowed_objects << 'Meter:CustomDecrement'
268
+
269
+ if allowed_objects.include?(idd_object.name)
270
+ unless check_for_object(workspace, idf_object, idd_object.type)
271
+ workspace.addObject(idf_object)
272
+ num_added += 1
273
+ end
274
+ end
275
+
276
+ allowed_unique_objects = []
277
+ # allowed_unique_objects << "Output:EnergyManagementSystem" # TODO: have to merge
278
+ # allowed_unique_objects << "OutputControl:SurfaceColorScheme" # TODO: have to merge
279
+ allowed_unique_objects << 'Output:Table:SummaryReports' # TODO: have to merge
280
+ # OutputControl:Table:Style # not allowed
281
+ # OutputControl:ReportingTolerances # not allowed
282
+ # Output:SQLite # not allowed
283
+
284
+ if allowed_unique_objects.include?(idf_object.iddObject.name)
285
+ if idf_object.iddObject.name == 'Output:Table:SummaryReports'
286
+ summary_reports = workspace.getObjectsByType(idf_object.iddObject.type)
287
+ if summary_reports.empty?
288
+ workspace.addObject(idf_object)
289
+ num_added += 1
290
+ else
291
+ merge_output_table_summary_reports(summary_reports[0], idf_object)
292
+ end
293
+ end
294
+ end
295
+
296
+ return num_added
297
+ end
298
+
299
+ # check to see if we have an exact match for this object already
300
+ def self.check_for_object(workspace, idf_object, idd_object_type)
301
+ workspace.getObjectsByType(idd_object_type).each do |object|
302
+ # all of these objects fields are data fields
303
+ if idf_object.dataFieldsEqual(object)
304
+ return true
305
+ end
306
+ end
307
+ return false
308
+ end
309
+
310
+ # merge all summary reports that are not in the current workspace
311
+ def self.merge_output_table_summary_reports(current_object, new_object)
312
+ current_fields = []
313
+ current_object.extensibleGroups.each do |current_extensible_group|
314
+ current_fields << current_extensible_group.getString(0).to_s
315
+ end
316
+
317
+ fields_to_add = []
318
+ new_object.extensibleGroups.each do |new_extensible_group|
319
+ field = new_extensible_group.getString(0).to_s
320
+ unless current_fields.include?(field)
321
+ current_fields << field
322
+ fields_to_add << field
323
+ end
324
+ end
325
+
326
+ unless fields_to_add.empty?
327
+ fields_to_add.each do |field|
328
+ values = OpenStudio::StringVector.new
329
+ values << field
330
+ current_object.pushExtensibleGroup(values)
331
+ end
332
+ return true
333
+ end
334
+
335
+ return false
336
+ end
337
+
338
+ def self.monthly_report_idf_text
339
+ <<-HEREDOC
340
+ Output:Table:Monthly,
341
+ Building Energy Performance - Electricity, !- Name
342
+ 2, !- Digits After Decimal
343
+ InteriorLights:Electricity, !- Variable or Meter 1 Name
344
+ SumOrAverage, !- Aggregation Type for Variable or Meter 1
345
+ ExteriorLights:Electricity, !- Variable or Meter 2 Name
346
+ SumOrAverage, !- Aggregation Type for Variable or Meter 2
347
+ InteriorEquipment:Electricity, !- Variable or Meter 3 Name
348
+ SumOrAverage, !- Aggregation Type for Variable or Meter 3
349
+ ExteriorEquipment:Electricity, !- Variable or Meter 4 Name
350
+ SumOrAverage, !- Aggregation Type for Variable or Meter 4
351
+ Fans:Electricity, !- Variable or Meter 5 Name
352
+ SumOrAverage, !- Aggregation Type for Variable or Meter 5
353
+ Pumps:Electricity, !- Variable or Meter 6 Name
354
+ SumOrAverage, !- Aggregation Type for Variable or Meter 6
355
+ Heating:Electricity, !- Variable or Meter 7 Name
356
+ SumOrAverage, !- Aggregation Type for Variable or Meter 7
357
+ Cooling:Electricity, !- Variable or Meter 8 Name
358
+ SumOrAverage, !- Aggregation Type for Variable or Meter 8
359
+ HeatRejection:Electricity, !- Variable or Meter 9 Name
360
+ SumOrAverage, !- Aggregation Type for Variable or Meter 9
361
+ Humidifier:Electricity, !- Variable or Meter 10 Name
362
+ SumOrAverage, !- Aggregation Type for Variable or Meter 10
363
+ HeatRecovery:Electricity,!- Variable or Meter 11 Name
364
+ SumOrAverage, !- Aggregation Type for Variable or Meter 11
365
+ WaterSystems:Electricity,!- Variable or Meter 12 Name
366
+ SumOrAverage, !- Aggregation Type for Variable or Meter 12
367
+ Cogeneration:Electricity,!- Variable or Meter 13 Name
368
+ SumOrAverage, !- Aggregation Type for Variable or Meter 13
369
+ Refrigeration:Electricity,!- Variable or Meter 14 Name
370
+ SumOrAverage; !- Aggregation Type for Variable or Meter 14
371
+
372
+ Output:Table:Monthly,
373
+ Building Energy Performance - Natural Gas, !- Name
374
+ 2, !- Digits After Decimal
375
+ InteriorEquipment:Gas, !- Variable or Meter 1 Name
376
+ SumOrAverage, !- Aggregation Type for Variable or Meter 1
377
+ ExteriorEquipment:Gas, !- Variable or Meter 2 Name
378
+ SumOrAverage, !- Aggregation Type for Variable or Meter 2
379
+ Heating:Gas, !- Variable or Meter 3 Name
380
+ SumOrAverage, !- Aggregation Type for Variable or Meter 3
381
+ Cooling:Gas, !- Variable or Meter 4 Name
382
+ SumOrAverage, !- Aggregation Type for Variable or Meter 4
383
+ WaterSystems:Gas, !- Variable or Meter 5 Name
384
+ SumOrAverage, !- Aggregation Type for Variable or Meter 5
385
+ Cogeneration:Gas, !- Variable or Meter 6 Name
386
+ SumOrAverage; !- Aggregation Type for Variable or Meter 6
387
+
388
+ Output:Table:Monthly,
389
+ Building Energy Performance - District Heating, !- Name
390
+ 2, !- Digits After Decimal
391
+ InteriorLights:DistrictHeating, !- Variable or Meter 1 Name
392
+ SumOrAverage, !- Aggregation Type for Variable or Meter 1
393
+ ExteriorLights:DistrictHeating, !- Variable or Meter 2 Name
394
+ SumOrAverage, !- Aggregation Type for Variable or Meter 2
395
+ InteriorEquipment:DistrictHeating, !- Variable or Meter 3 Name
396
+ SumOrAverage, !- Aggregation Type for Variable or Meter 3
397
+ ExteriorEquipment:DistrictHeating, !- Variable or Meter 4 Name
398
+ SumOrAverage, !- Aggregation Type for Variable or Meter 4
399
+ Fans:DistrictHeating, !- Variable or Meter 5 Name
400
+ SumOrAverage, !- Aggregation Type for Variable or Meter 5
401
+ Pumps:DistrictHeating, !- Variable or Meter 6 Name
402
+ SumOrAverage, !- Aggregation Type for Variable or Meter 6
403
+ Heating:DistrictHeating, !- Variable or Meter 7 Name
404
+ SumOrAverage, !- Aggregation Type for Variable or Meter 7
405
+ Cooling:DistrictHeating, !- Variable or Meter 8 Name
406
+ SumOrAverage, !- Aggregation Type for Variable or Meter 8
407
+ HeatRejection:DistrictHeating, !- Variable or Meter 9 Name
408
+ SumOrAverage, !- Aggregation Type for Variable or Meter 9
409
+ Humidifier:DistrictHeating, !- Variable or Meter 10 Name
410
+ SumOrAverage, !- Aggregation Type for Variable or Meter 10
411
+ HeatRecovery:DistrictHeating,!- Variable or Meter 11 Name
412
+ SumOrAverage, !- Aggregation Type for Variable or Meter 11
413
+ WaterSystems:DistrictHeating,!- Variable or Meter 12 Name
414
+ SumOrAverage, !- Aggregation Type for Variable or Meter 12
415
+ Cogeneration:DistrictHeating,!- Variable or Meter 13 Name
416
+ SumOrAverage; !- Aggregation Type for Variable or Meter 13
417
+
418
+ Output:Table:Monthly,
419
+ Building Energy Performance - District Cooling, !- Name
420
+ 2, !- Digits After Decimal
421
+ InteriorLights:DistrictCooling, !- Variable or Meter 1 Name
422
+ SumOrAverage, !- Aggregation Type for Variable or Meter 1
423
+ ExteriorLights:DistrictCooling, !- Variable or Meter 2 Name
424
+ SumOrAverage, !- Aggregation Type for Variable or Meter 2
425
+ InteriorEquipment:DistrictCooling, !- Variable or Meter 3 Name
426
+ SumOrAverage, !- Aggregation Type for Variable or Meter 3
427
+ ExteriorEquipment:DistrictCooling, !- Variable or Meter 4 Name
428
+ SumOrAverage, !- Aggregation Type for Variable or Meter 4
429
+ Fans:DistrictCooling, !- Variable or Meter 5 Name
430
+ SumOrAverage, !- Aggregation Type for Variable or Meter 5
431
+ Pumps:DistrictCooling, !- Variable or Meter 6 Name
432
+ SumOrAverage, !- Aggregation Type for Variable or Meter 6
433
+ Heating:DistrictCooling, !- Variable or Meter 7 Name
434
+ SumOrAverage, !- Aggregation Type for Variable or Meter 7
435
+ Cooling:DistrictCooling, !- Variable or Meter 8 Name
436
+ SumOrAverage, !- Aggregation Type for Variable or Meter 8
437
+ HeatRejection:DistrictCooling, !- Variable or Meter 9 Name
438
+ SumOrAverage, !- Aggregation Type for Variable or Meter 9
439
+ Humidifier:DistrictCooling, !- Variable or Meter 10 Name
440
+ SumOrAverage, !- Aggregation Type for Variable or Meter 10
441
+ HeatRecovery:DistrictCooling,!- Variable or Meter 11 Name
442
+ SumOrAverage, !- Aggregation Type for Variable or Meter 11
443
+ WaterSystems:DistrictCooling,!- Variable or Meter 12 Name
444
+ SumOrAverage, !- Aggregation Type for Variable or Meter 12
445
+ Cogeneration:DistrictCooling,!- Variable or Meter 13 Name
446
+ SumOrAverage; !- Aggregation Type for Variable or Meter 13
447
+
448
+ Output:Table:Monthly,
449
+ Building Energy Performance - Electricity Peak Demand, !- Name
450
+ 2, !- Digits After Decimal
451
+ Electricity:Facility, !- Variable or Meter 1 Name
452
+ Maximum, !- Aggregation Type for Variable or Meter 1
453
+ InteriorLights:Electricity, !- Variable or Meter 1 Name
454
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 1
455
+ ExteriorLights:Electricity, !- Variable or Meter 2 Name
456
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 2
457
+ InteriorEquipment:Electricity, !- Variable or Meter 3 Name
458
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 3
459
+ ExteriorEquipment:Electricity, !- Variable or Meter 4 Name
460
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 4
461
+ Fans:Electricity, !- Variable or Meter 5 Name
462
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 5
463
+ Pumps:Electricity, !- Variable or Meter 6 Name
464
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 6
465
+ Heating:Electricity, !- Variable or Meter 7 Name
466
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 7
467
+ Cooling:Electricity, !- Variable or Meter 8 Name
468
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 8
469
+ HeatRejection:Electricity, !- Variable or Meter 9 Name
470
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 9
471
+ Humidifier:Electricity, !- Variable or Meter 10 Name
472
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 10
473
+ HeatRecovery:Electricity,!- Variable or Meter 11 Name
474
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 11
475
+ WaterSystems:Electricity,!- Variable or Meter 12 Name
476
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 12
477
+ Cogeneration:Electricity,!- Variable or Meter 13 Name
478
+ ValueWhenMaximumOrMinimum; !- Aggregation Type for Variable or Meter 13
479
+
480
+ Output:Table:Monthly,
481
+ Building Energy Performance - Natural Gas Peak Demand, !- Name
482
+ 2, !- Digits After Decimal
483
+ Gas:Facility, !- Variable or Meter 1 Name
484
+ Maximum, !- Aggregation Type for Variable or Meter 1
485
+ InteriorEquipment:Gas, !- Variable or Meter 1 Name
486
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 1
487
+ ExteriorEquipment:Gas, !- Variable or Meter 2 Name
488
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 2
489
+ Heating:Gas, !- Variable or Meter 3 Name
490
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 3
491
+ Cooling:Gas, !- Variable or Meter 4 Name
492
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 4
493
+ WaterSystems:Gas, !- Variable or Meter 5 Name
494
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 5
495
+ Cogeneration:Gas, !- Variable or Meter 6 Name
496
+ ValueWhenMaximumOrMinimum; !- Aggregation Type for Variable or Meter 6
497
+
498
+ Output:Table:Monthly,
499
+ Building Energy Performance - District Heating Peak Demand, !- Name
500
+ 2, !- Digits After Decimal
501
+ DistrictHeating:Facility, !- Variable or Meter 1 Name
502
+ Maximum, !- Aggregation Type for Variable or Meter 1
503
+ InteriorLights:DistrictHeating, !- Variable or Meter 1 Name
504
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 1
505
+ ExteriorLights:DistrictHeating, !- Variable or Meter 2 Name
506
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 2
507
+ InteriorEquipment:DistrictHeating, !- Variable or Meter 3 Name
508
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 3
509
+ ExteriorEquipment:DistrictHeating, !- Variable or Meter 4 Name
510
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 4
511
+ Fans:DistrictHeating, !- Variable or Meter 5 Name
512
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 5
513
+ Pumps:DistrictHeating, !- Variable or Meter 6 Name
514
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 6
515
+ Heating:DistrictHeating, !- Variable or Meter 7 Name
516
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 7
517
+ Cooling:DistrictHeating, !- Variable or Meter 8 Name
518
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 8
519
+ HeatRejection:DistrictHeating, !- Variable or Meter 9 Name
520
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 9
521
+ Humidifier:DistrictHeating, !- Variable or Meter 10 Name
522
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 10
523
+ HeatRecovery:DistrictHeating,!- Variable or Meter 11 Name
524
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 11
525
+ WaterSystems:DistrictHeating,!- Variable or Meter 12 Name
526
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 12
527
+ Cogeneration:DistrictHeating,!- Variable or Meter 13 Name
528
+ ValueWhenMaximumOrMinimum; !- Aggregation Type for Variable or Meter 13
529
+
530
+ Output:Table:Monthly,
531
+ Building Energy Performance - District Cooling Peak Demand, !- Name
532
+ 2, !- Digits After Decimal
533
+ DistrictCooling:Facility, !- Variable or Meter 1 Name
534
+ Maximum, !- Aggregation Type for Variable or Meter 1
535
+ InteriorLights:DistrictCooling, !- Variable or Meter 1 Name
536
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 1
537
+ ExteriorLights:DistrictCooling, !- Variable or Meter 2 Name
538
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 2
539
+ InteriorEquipment:DistrictCooling, !- Variable or Meter 3 Name
540
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 3
541
+ ExteriorEquipment:DistrictCooling, !- Variable or Meter 4 Name
542
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 4
543
+ Fans:DistrictCooling, !- Variable or Meter 5 Name
544
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 5
545
+ Pumps:DistrictCooling, !- Variable or Meter 6 Name
546
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 6
547
+ Heating:DistrictCooling, !- Variable or Meter 7 Name
548
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 7
549
+ Cooling:DistrictCooling, !- Variable or Meter 8 Name
550
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 8
551
+ HeatRejection:DistrictCooling, !- Variable or Meter 9 Name
552
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 9
553
+ Humidifier:DistrictCooling, !- Variable or Meter 10 Name
554
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 10
555
+ HeatRecovery:DistrictCooling,!- Variable or Meter 11 Name
556
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 11
557
+ WaterSystems:DistrictCooling,!- Variable or Meter 12 Name
558
+ ValueWhenMaximumOrMinimum, !- Aggregation Type for Variable or Meter 12
559
+ Cogeneration:DistrictCooling,!- Variable or Meter 13 Name
560
+ ValueWhenMaximumOrMinimum; !- Aggregation Type for Variable or Meter 13
561
+ HEREDOC
562
+ end
563
+ end
564
+ end
565
+ end
566
+ end