openstudio-workflow 1.3.3 → 1.3.4

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