openstudio-workflow 1.2.0 → 1.2.1

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 +48 -48
  4. data/Rakefile +36 -36
  5. data/lib/openstudio/workflow/adapters/input/local.rb +240 -240
  6. data/lib/openstudio/workflow/adapters/output/local.rb +95 -95
  7. data/lib/openstudio/workflow/adapters/output/socket.rb +91 -91
  8. data/lib/openstudio/workflow/adapters/output/web.rb +66 -66
  9. data/lib/openstudio/workflow/adapters/output_adapter.rb +147 -147
  10. data/lib/openstudio/workflow/job.rb +22 -22
  11. data/lib/openstudio/workflow/jobs/resources/monthly_report.idf +222 -222
  12. data/lib/openstudio/workflow/jobs/run_energyplus.rb +49 -49
  13. data/lib/openstudio/workflow/jobs/run_ep_measures.rb +55 -55
  14. data/lib/openstudio/workflow/jobs/run_initialization.rb +167 -167
  15. data/lib/openstudio/workflow/jobs/run_os_measures.rb +69 -69
  16. data/lib/openstudio/workflow/jobs/run_postprocess.rb +53 -53
  17. data/lib/openstudio/workflow/jobs/run_preprocess.rb +69 -69
  18. data/lib/openstudio/workflow/jobs/run_reporting_measures.rb +98 -98
  19. data/lib/openstudio/workflow/jobs/run_translation.rb +61 -61
  20. data/lib/openstudio/workflow/multi_delegator.rb +46 -46
  21. data/lib/openstudio/workflow/registry.rb +137 -137
  22. data/lib/openstudio/workflow/run.rb +299 -299
  23. data/lib/openstudio/workflow/time_logger.rb +53 -53
  24. data/lib/openstudio/workflow/util/energyplus.rb +564 -564
  25. data/lib/openstudio/workflow/util/io.rb +33 -33
  26. data/lib/openstudio/workflow/util/measure.rb +588 -586
  27. data/lib/openstudio/workflow/util/model.rb +100 -100
  28. data/lib/openstudio/workflow/util/post_process.rb +187 -187
  29. data/lib/openstudio/workflow/util/weather_file.rb +108 -108
  30. data/lib/openstudio/workflow/util.rb +14 -14
  31. data/lib/openstudio/workflow/version.rb +24 -24
  32. data/lib/openstudio/workflow_json.rb +426 -426
  33. data/lib/openstudio/workflow_runner.rb +215 -215
  34. data/lib/openstudio-workflow.rb +49 -49
  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,564 +1,564 @@
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
+ 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