openstudio-workflow 1.3.3 → 1.3.4

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 +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