openstudio-workflow 1.2.1 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
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