openstudio-workflow 2.2.1 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/lib/openstudio/workflow/adapters/input/local.rb +95 -0
- data/lib/openstudio/workflow/run.rb +4 -0
- data/lib/openstudio/workflow/util/energyplus.rb +47 -11
- data/lib/openstudio/workflow/util/model.rb +59 -2
- data/lib/openstudio/workflow/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fcb791c63593c4b0a7c7050c243c4e7214e8e62f04d3f4e3c29652c6690b5372
|
4
|
+
data.tar.gz: c831e36b5024f861eee6a46e5fc751ec0dc965a4e358fd0532ad293069acfc4f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5191c3ec1be4a4b801afb357f46ef35b127a73b92c0c0d5c2831f1bb3374ec365675c6baa70e2513884ab87d5f6ffb80f69e540f90310db6ea99cf1d1962fe56
|
7
|
+
data.tar.gz: 7aceb6c2b096e47522ed68b978f3e36d46c8dd2dd79ace0a7b5415a685078dfd9852f75e626c98ea2d875e4365ae5787ea6a5007178fbda5b84490868b92ff30
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
OpenStudio::Workflow Change Log
|
2
2
|
==================================
|
3
3
|
|
4
|
+
Version 2.3.0
|
5
|
+
-------------
|
6
|
+
* Feature [#135](https://github.com/NREL/OpenStudio-workflow-gem/issues/135) Add option to export/run epJSON
|
7
|
+
|
4
8
|
Version 2.2.1
|
5
9
|
-------------
|
6
10
|
* Fixes [#4150](https://github.com/NREL/OpenStudio/issues/4150) LoadError changes current working directory in CLI
|
@@ -291,6 +291,101 @@ module OpenStudio
|
|
291
291
|
return default
|
292
292
|
end
|
293
293
|
|
294
|
+
def epjson(user_options, default, logger)
|
295
|
+
# check version for this feature
|
296
|
+
os_version = OpenStudio::VersionString.new(OpenStudio.openStudioVersion)
|
297
|
+
min_version_feature = OpenStudio::VersionString.new('3.3.0')
|
298
|
+
unless os_version >= min_version_feature
|
299
|
+
log_message = 'epJSON is only supported for versions >= 3.3.0. Falling back to using IDF'
|
300
|
+
logger.info log_message
|
301
|
+
return default
|
302
|
+
end
|
303
|
+
|
304
|
+
# user option trumps all others
|
305
|
+
return user_options[:epjson] if user_options[:epjson]
|
306
|
+
|
307
|
+
# try to read from OSW
|
308
|
+
|
309
|
+
if @run_options.is_initialized && @run_options.get.respond_to?(:epjson)
|
310
|
+
return @run_options.get.epjson
|
311
|
+
end
|
312
|
+
|
313
|
+
return default
|
314
|
+
end
|
315
|
+
|
316
|
+
# Process the `run` method `ft_options` subhash
|
317
|
+
#
|
318
|
+
# This will validate that each suboption is supported in the current
|
319
|
+
# version as well as enhance the hash with the corresponding
|
320
|
+
# ForwardTranslator method name to set the value on the FT later
|
321
|
+
# in `translate_to_energyplus`
|
322
|
+
# user option trumps all others
|
323
|
+
def ft_options(user_options, default, logger)
|
324
|
+
# check version for this feature
|
325
|
+
os_version = OpenStudio::VersionString.new(OpenStudio.openStudioVersion)
|
326
|
+
|
327
|
+
os300 = OpenStudio::VersionString.new('3.0.0')
|
328
|
+
os330 = OpenStudio::VersionString.new('3.3.0')
|
329
|
+
known_ft_opts = {
|
330
|
+
# All Versions
|
331
|
+
runcontrolspecialdays: { method_name: :setKeepRunControlSpecialDays, min_version: nil },
|
332
|
+
ip_tabular_output: { method_name: :setIPTabularOutput, min_version: nil },
|
333
|
+
no_lifecyclecosts: { method_name: :setExcludeLCCObjects, min_version: nil },
|
334
|
+
# 3.0.0
|
335
|
+
no_sqlite_output: { method_name: :setExcludeSQliteOutputReport, min_version: os300 },
|
336
|
+
no_html_output: { method_name: :setExcludeHTMLOutputReport, min_version: os300 },
|
337
|
+
no_variable_dictionary: { method_name: :setExcludeVariableDictionary, min_version: os300 },
|
338
|
+
# 3.3.0
|
339
|
+
no_space_translation: { method_name: :setExcludeSpaceTranslation, min_version: os330 }
|
340
|
+
}
|
341
|
+
|
342
|
+
# user option trumps all others
|
343
|
+
if user_options[:ft_options]
|
344
|
+
ft_opts = {}
|
345
|
+
user_options[:ft_options].each do |opt_flag_name, opt_flag|
|
346
|
+
puts "#{opt_flag_name} = #{opt_flag}"
|
347
|
+
unless known_ft_opts.key?(opt_flag_name)
|
348
|
+
log_message = "'ft_options' suboption '#{opt_flag_name}' is not recognized, ignoring it."
|
349
|
+
logger.warn log_message
|
350
|
+
next
|
351
|
+
end
|
352
|
+
min_version = known_ft_opts[opt_flag_name][:min_version]
|
353
|
+
if !min_version.nil? && os_version < min_version
|
354
|
+
log_message = "'ft_options' suboption '#{opt_flag_name}' is only supported for OpenStudio Version >= #{min_version.str}, ignoring it."
|
355
|
+
logger.warn log_message
|
356
|
+
next
|
357
|
+
end
|
358
|
+
ft_opts[opt_flag_name] = { method_name: known_ft_opts[opt_flag_name][:method_name], value: opt_flag }
|
359
|
+
end
|
360
|
+
|
361
|
+
return ft_opts
|
362
|
+
end
|
363
|
+
|
364
|
+
# try to read from OSW
|
365
|
+
|
366
|
+
if @run_options.is_initialized && @run_options.get.respond_to?(:forwardTranslateOptions)
|
367
|
+
ft_opts = {}
|
368
|
+
JSON.parse(@run_options.get.forwardTranslateOptions, symbolize_names: true).each do |opt_flag_name, opt_flag|
|
369
|
+
unless known_ft_opts.key?(opt_flag_name)
|
370
|
+
log_message = "'ft_options' suboption '#{opt_flag_name}' is not recognized, ignoring it."
|
371
|
+
logger.warn log_message
|
372
|
+
next
|
373
|
+
end
|
374
|
+
min_version = known_ft_opts[opt_flag_name.to_sym][:min_version]
|
375
|
+
if !min_version.nil? && os_version < min_version
|
376
|
+
log_message = "'ft_options' suboption '#{opt_flag_name}' is only supported for OpenStudio Version >= #{min_version.str}, ignoring it."
|
377
|
+
logger.warn log_message
|
378
|
+
next
|
379
|
+
end
|
380
|
+
ft_opts[opt_flag_name] = { method_name: known_ft_opts[opt_flag_name][:method_name], value: opt_flag }
|
381
|
+
end
|
382
|
+
|
383
|
+
return ft_opts
|
384
|
+
end
|
385
|
+
|
386
|
+
return default
|
387
|
+
end
|
388
|
+
|
294
389
|
def weather_file(user_options, default)
|
295
390
|
# user option trumps all others
|
296
391
|
return user_options[:weather_file] if user_options[:weather_file]
|
@@ -95,6 +95,8 @@ module OpenStudio
|
|
95
95
|
# @option user_options [Hash] :targets Log targets to write to, defaults to standard out and run.log
|
96
96
|
# @option user_options [Hash] :verify_osw Check OSW for correctness, defaults to true
|
97
97
|
# @option user_options [Hash] :weather_file Initial weather file to load, overrides OSW option if set, defaults to empty
|
98
|
+
# @option user_options [Hash] :epjson - Create, export and run using epjson format. Default is IDF
|
99
|
+
# @option user_options [Hash] :ft_options - A subhash of options to set on the ForwardTranslator
|
98
100
|
def initialize(osw_path, user_options = {})
|
99
101
|
# DLM - what is final_message?
|
100
102
|
@final_message = ''
|
@@ -199,6 +201,8 @@ module OpenStudio
|
|
199
201
|
@options[:weather_file] = @input_adapter.weather_file(user_options, nil)
|
200
202
|
@options[:fast] = @input_adapter.fast(user_options, false)
|
201
203
|
@options[:skip_zip_results] = @input_adapter.skip_zip_results(user_options, false)
|
204
|
+
@options[:epjson] = @input_adapter.epjson(user_options, false, @logger)
|
205
|
+
@options[:ft_options] = @input_adapter.ft_options(user_options, {}, @logger)
|
202
206
|
|
203
207
|
openstudio_dir = 'unknown'
|
204
208
|
begin
|
@@ -43,6 +43,8 @@ module OpenStudio
|
|
43
43
|
module EnergyPlus
|
44
44
|
require 'openstudio/workflow/util/io'
|
45
45
|
include OpenStudio::Workflow::Util::IO
|
46
|
+
require 'openstudio/workflow/util/model'
|
47
|
+
include OpenStudio::Workflow::Util::Model
|
46
48
|
ENERGYPLUS_REGEX = /^energyplus\D{0,4}$/i.freeze
|
47
49
|
EXPAND_OBJECTS_REGEX = /^expandobjects\D{0,4}$/i.freeze
|
48
50
|
|
@@ -94,8 +96,8 @@ module OpenStudio
|
|
94
96
|
Dir["#{energyplus_path}/*"].each do |file|
|
95
97
|
next if File.directory? file
|
96
98
|
|
97
|
-
# copy idd and
|
98
|
-
if File.extname(file).downcase =~ /.idd|.ini/
|
99
|
+
# copy idd, ini and epJSON schema files
|
100
|
+
if File.extname(file).downcase =~ /.idd|.ini|.epjson/
|
99
101
|
dest_file = "#{run_directory}/#{File.basename(file)}"
|
100
102
|
energyplus_files << dest_file
|
101
103
|
FileUtils.copy file, dest_file
|
@@ -130,7 +132,9 @@ module OpenStudio
|
|
130
132
|
current_dir = Dir.pwd
|
131
133
|
energyplus_path ||= find_energyplus
|
132
134
|
logger.info "EnergyPlus path is #{energyplus_path}"
|
135
|
+
|
133
136
|
energyplus_files, energyplus_exe, expand_objects_exe = prepare_energyplus_dir(run_directory, logger, energyplus_path)
|
137
|
+
|
134
138
|
Dir.chdir(run_directory)
|
135
139
|
logger.info "Starting simulation in run directory: #{Dir.pwd}"
|
136
140
|
|
@@ -152,18 +156,50 @@ module OpenStudio
|
|
152
156
|
end
|
153
157
|
end
|
154
158
|
|
155
|
-
#
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
159
|
+
# Translate the IDF to an epJSON if @options[:epjson] is true
|
160
|
+
# Ideally, this would be done sooner in the workflow process but many processes
|
161
|
+
# manipulate the model_idf, some which are ep_measures that may not work with json
|
162
|
+
# and ExpandObjects does not currently support epjson anyway to that still needs to run
|
163
|
+
# before this can be changed.
|
164
|
+
if @options[:epjson]
|
165
|
+
@logger.info 'Beginning the translation to epJSON'
|
166
|
+
@registry[:time_logger]&.start('Translating to EnergyPlus epJSON')
|
167
|
+
idf_final = load_idf("#{run_directory}/in.idf", @logger)
|
168
|
+
model_epjson = translate_idf_to_epjson idf_final, @logger
|
169
|
+
@registry[:time_logger]&.stop('Translating to EnergyPlus')
|
170
|
+
@logger.info 'Successfully translated to epJSON'
|
171
|
+
@registry[:time_logger]&.start('Saving epJSON')
|
172
|
+
epjson_name = save_epjson(model_epjson, run_directory)
|
173
|
+
@registry[:time_logger]&.stop('Saving epJSON')
|
174
|
+
@logger.debug "Saved epJSON as #{epjson_name}"
|
175
|
+
end
|
176
|
+
|
177
|
+
# Run using epJSON if @options[:epjson] true, otherwise use IDF
|
178
|
+
if @options[:epjson]
|
179
|
+
command = popen_command("\"#{energyplus_exe}\" in.epJSON 2>&1")
|
180
|
+
logger.info "Running command '#{command}'"
|
181
|
+
File.open('stdout-energyplus', 'w') do |file|
|
182
|
+
::IO.popen(command) do |io|
|
183
|
+
while (line = io.gets)
|
184
|
+
file << line
|
185
|
+
output_adapter&.communicate_energyplus_stdout(line)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
r = $?
|
190
|
+
else
|
191
|
+
command = popen_command("\"#{energyplus_exe}\" 2>&1")
|
192
|
+
logger.info "Running command '#{command}'"
|
193
|
+
File.open('stdout-energyplus', 'w') do |file|
|
194
|
+
::IO.popen(command) do |io|
|
195
|
+
while (line = io.gets)
|
196
|
+
file << line
|
197
|
+
output_adapter&.communicate_energyplus_stdout(line)
|
198
|
+
end
|
163
199
|
end
|
164
200
|
end
|
201
|
+
r = $?
|
165
202
|
end
|
166
|
-
r = $?
|
167
203
|
|
168
204
|
logger.info "EnergyPlus returned '#{r}'"
|
169
205
|
unless r.to_i.zero?
|
@@ -101,13 +101,49 @@ module OpenStudio
|
|
101
101
|
# ensure objects exist for reporting purposes
|
102
102
|
model.getFacility
|
103
103
|
model.getBuilding
|
104
|
-
|
105
|
-
|
104
|
+
ft = OpenStudio::EnergyPlus::ForwardTranslator.new
|
105
|
+
|
106
|
+
ft_options = @options[:ft_options]
|
107
|
+
if !ft_options.empty?
|
108
|
+
|
109
|
+
msg = "Custom ForwardTranslator options passed:\n"
|
110
|
+
|
111
|
+
ft_options.each do |opt_flag_name, h|
|
112
|
+
ft_method = h[:method_name]
|
113
|
+
opt_flag = h[:value]
|
114
|
+
|
115
|
+
# Call the FT setter with the value passed in
|
116
|
+
ft.method(ft_method).call(opt_flag)
|
117
|
+
|
118
|
+
msg += "* :#{opt_flag_name}=#{opt_flag} => ft.#{ft_method}(#{opt_flag})\n"
|
119
|
+
end
|
120
|
+
|
121
|
+
logger.info msg
|
122
|
+
end
|
123
|
+
|
124
|
+
model_idf = ft.translateModel(model)
|
106
125
|
b = ::Time.now
|
107
126
|
logger.info "Translate object to EnergyPlus IDF took #{b.to_f - a.to_f}"
|
108
127
|
model_idf
|
109
128
|
end
|
110
129
|
|
130
|
+
# Translates an IDF model into an EnergyPlus epJSON object
|
131
|
+
#
|
132
|
+
# @param [Object] OpenStudio::IdfFile instance to translate into an OpenStudio epJSON object -- see
|
133
|
+
# the OpenStudio SDK for details on the process
|
134
|
+
# @return [Object] Returns and OpenStudio::epJSONobject
|
135
|
+
#
|
136
|
+
def translate_idf_to_epjson(model_idf, logger = nil)
|
137
|
+
logger ||= ::Logger.new($stdout)
|
138
|
+
logger.info 'Translate IDF to epJSON in preparation for EnergyPlus'
|
139
|
+
a = ::Time.now
|
140
|
+
model_epjson = OpenStudio::EPJSON.toJSONString(model_idf)
|
141
|
+
b = ::Time.now
|
142
|
+
logger.info "Translate IDF to EnergyPlus epJSON took #{b.to_f - a.to_f}"
|
143
|
+
|
144
|
+
model_epjson
|
145
|
+
end
|
146
|
+
|
111
147
|
# Saves an OpenStudio model object to file
|
112
148
|
#
|
113
149
|
# @param [Object] model The OpenStudio::Model instance to save to file
|
@@ -149,6 +185,27 @@ module OpenStudio
|
|
149
185
|
end
|
150
186
|
idf_filename
|
151
187
|
end
|
188
|
+
|
189
|
+
# Saves an OpenStudio EpJSON model object to file
|
190
|
+
#
|
191
|
+
# @param [Object] model The OpenStudio::Workspace instance to save to file
|
192
|
+
# @param [String] save_directory Folder to save the model in
|
193
|
+
# @param [String] name ('in.epJSON') Option to define a non-standard name
|
194
|
+
# @return [String] epJSON file name
|
195
|
+
#
|
196
|
+
def save_epjson(model_epjson, save_directory, name = 'in.epJSON')
|
197
|
+
epjson_filename = File.join(save_directory.to_s, name.to_s)
|
198
|
+
File.open(epjson_filename, 'w') do |f|
|
199
|
+
f << model_epjson.to_s
|
200
|
+
# make sure data is written to the disk one way or the other
|
201
|
+
begin
|
202
|
+
f.fsync
|
203
|
+
rescue StandardError
|
204
|
+
f.flush
|
205
|
+
end
|
206
|
+
end
|
207
|
+
epjson_filename
|
208
|
+
end
|
152
209
|
end
|
153
210
|
end
|
154
211
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: openstudio-workflow
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nicholas Long
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2021-
|
12
|
+
date: 2021-10-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: builder
|